rift-ds 1.4.0 → 1.6.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/README.md +3 -3
- package/components/AppSidebar/AppSidebar.css +6 -0
- package/components/AppSidebar/AppSidebar.d.ts +12 -2
- package/components/AppSidebar/AppSidebar.js +11 -1
- package/components/ContextMenu/ContextMenu.css +25 -0
- package/components/ContextMenu/ContextMenu.js +14 -6
- package/components/DropdownMenu/DropdownMenu.css +29 -0
- package/components/DropdownMenu/DropdownMenu.d.ts +2 -0
- package/components/DropdownMenu/DropdownMenu.js +15 -7
- package/components/PixelAvatar/PixelAvatar.css +79 -0
- package/components/PixelAvatar/PixelAvatar.d.ts +47 -0
- package/components/PixelAvatar/PixelAvatar.js +90 -0
- package/components/PixelAvatar/pixelInks.d.ts +27 -0
- package/components/PixelAvatar/pixelInks.js +45 -0
- package/components/PromptSuggestions/PromptSuggestions.css +218 -0
- package/components/PromptSuggestions/PromptSuggestions.d.ts +10 -3
- package/components/PromptSuggestions/PromptSuggestions.js +26 -3
- package/components/Quote/Quote.css +2 -2
- package/components/ShaderField/useShaderField.d.ts +4 -4
- package/components/SourceChip/SourceChip.css +211 -11
- package/components/SourceChip/SourceChip.d.ts +33 -10
- package/components/SourceChip/SourceChip.js +174 -22
- package/components/Stat/Stat.css +2 -2
- package/components/ThreadPanel/ThreadPanel.css +6 -0
- package/components/ThreadPanel/ThreadPanel.d.ts +3 -1
- package/components/ThreadPanel/ThreadPanel.js +22 -4
- package/components/Widget/Widget.css +207 -0
- package/components/Widget/Widget.d.ts +83 -0
- package/components/Widget/Widget.js +112 -0
- package/components/registry.json +17 -1
- package/components/registry.json.d.ts +17 -1
- package/components/registry.json.js +1 -1
- package/fonts/presets/fredoka-300-700-latin-ext.woff2 +0 -0
- package/fonts/presets/fredoka-300-700-latin.woff2 +0 -0
- package/fonts/presets/manrope-300-800-latin-ext.woff2 +0 -0
- package/fonts/presets/manrope-300-800-latin.woff2 +0 -0
- package/fonts/presets/nunito-300-800-latin-ext.woff2 +0 -0
- package/fonts/presets/nunito-300-800-latin.woff2 +0 -0
- package/fonts/presets/playfair-display-400-800-latin-ext.woff2 +0 -0
- package/fonts/presets/playfair-display-400-800-latin.woff2 +0 -0
- package/fonts/presets/plus-jakarta-sans-300-800-latin-ext.woff2 +0 -0
- package/fonts/presets/plus-jakarta-sans-300-800-latin.woff2 +0 -0
- package/fonts/presets/source-sans-3-300-700-latin.woff2 +0 -0
- package/index.d.ts +2 -0
- package/index.js +10 -0
- package/package.json +1 -1
- package/tokens/presets/contrast.css +9 -9
- package/tokens/presets/coral.css +6 -6
- package/tokens/presets/forest.css +10 -10
- package/tokens/presets/gold.css +119 -11
- package/tokens/presets/mono.css +2 -2
- package/tokens/presets/pink.css +104 -24
- package/tokens/presets/terminal.css +13 -13
- package/tokens/presets/violet.css +114 -26
- package/tokens/presets/warm.css +10 -10
- package/tokens/presets/zest.css +10 -10
- package/tokens/registry.json +6 -0
- package/tokens/registry.json.d.ts +6 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +9 -0
- package/tokens/tokens-light.css +14 -0
- package/tokens/tokens-typography.css +1 -1
- package/fonts/presets/fraunces-300-700-latin-ext.woff2 +0 -0
- package/fonts/presets/fraunces-300-700-latin.woff2 +0 -0
- package/fonts/presets/work-sans-300-700-latin-ext.woff2 +0 -0
- package/fonts/presets/work-sans-300-700-latin.woff2 +0 -0
|
@@ -77,6 +77,224 @@
|
|
|
77
77
|
align-items: flex-start;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/* ============================================
|
|
81
|
+
TILES and CARDS — blocks for a home screen
|
|
82
|
+
Where the chip layouts are a line of prompts,
|
|
83
|
+
these are a row of places to start: an even
|
|
84
|
+
grid that folds as the row's own width narrows,
|
|
85
|
+
so a docked panel folds while a full-width page
|
|
86
|
+
does not.
|
|
87
|
+
============================================ */
|
|
88
|
+
|
|
89
|
+
/* The column floor is stated on the icon scale, the one size both blocks
|
|
90
|
+
are drawn from: a tile is never narrower than three cover icons, a card
|
|
91
|
+
than four. Four tiles or three cards sit in one row on a conversation
|
|
92
|
+
column and fold to two columns and one on a phone, with no breakpoint. */
|
|
93
|
+
.ds-prompt-suggestions--tiles,
|
|
94
|
+
.ds-prompt-suggestions--cards {
|
|
95
|
+
display: grid;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.ds-prompt-suggestions--tiles {
|
|
99
|
+
grid-template-columns: repeat(auto-fit, minmax(calc(var(--icon-size-1200) * 3), 1fr));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ds-prompt-suggestions--cards {
|
|
103
|
+
grid-template-columns: repeat(auto-fit, minmax(calc(var(--icon-size-1200) * 4), 1fr));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ds-prompt-suggestions--tiles .ds-prompt-suggestions__item,
|
|
107
|
+
.ds-prompt-suggestions--cards .ds-prompt-suggestions__item {
|
|
108
|
+
flex-shrink: 1;
|
|
109
|
+
min-width: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* One surface for both blocks: a hairline round a container that lets the
|
|
113
|
+
page through, blurred so text stays on a calm field over an ambient
|
|
114
|
+
background. The navigation-tile radius, per the radius scale. */
|
|
115
|
+
.ds-prompt-suggestions__tile,
|
|
116
|
+
.ds-prompt-suggestions__card {
|
|
117
|
+
display: flex;
|
|
118
|
+
flex-direction: column;
|
|
119
|
+
box-sizing: border-box;
|
|
120
|
+
width: 100%;
|
|
121
|
+
min-width: 0;
|
|
122
|
+
margin: 0;
|
|
123
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
124
|
+
border-radius: var(--radius-600);
|
|
125
|
+
background-color: var(--color-bg-container-primary-semi);
|
|
126
|
+
-webkit-backdrop-filter: blur(24px);
|
|
127
|
+
backdrop-filter: blur(24px);
|
|
128
|
+
color: inherit;
|
|
129
|
+
font: inherit;
|
|
130
|
+
text-align: left;
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* A tile answers the pointer quietly, in place: the fill firms up to the
|
|
135
|
+
solid container and the hairline steps up to the tertiary text ink, so
|
|
136
|
+
the block reads as picked out without moving. */
|
|
137
|
+
.ds-prompt-suggestions__tile {
|
|
138
|
+
transition:
|
|
139
|
+
background-color var(--motion-duration-fast) var(--motion-ease-standard),
|
|
140
|
+
border-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.ds-prompt-suggestions__tile:hover {
|
|
144
|
+
background-color: var(--color-bg-container-primary);
|
|
145
|
+
border-color: var(--color-text-tertiary);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* A card lifts: the Card component's own hover, the same rise and the same
|
|
149
|
+
sanctioned shadow, so a prompt card and a navigation tile answer the
|
|
150
|
+
pointer the same way. */
|
|
151
|
+
.ds-prompt-suggestions__card {
|
|
152
|
+
transition:
|
|
153
|
+
transform var(--motion-duration-slow) var(--motion-ease-standard),
|
|
154
|
+
box-shadow var(--motion-duration-slow) var(--motion-ease-standard);
|
|
155
|
+
/* ds-allow(color): transparent resting state of the sanctioned Card
|
|
156
|
+
hover-lift shadow (see design.md — Do's and Don'ts). */
|
|
157
|
+
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.ds-prompt-suggestions__card:hover {
|
|
161
|
+
transform: translateY(-4px);
|
|
162
|
+
/* ds-allow(color): the sanctioned Card hover-lift shadow, restated so the
|
|
163
|
+
two tiles lift alike (see design.md — Do's and Don'ts). */
|
|
164
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* The pending shells are not targets, so they neither lift nor light. */
|
|
168
|
+
.ds-prompt-suggestions__tile--pending:hover {
|
|
169
|
+
background-color: var(--color-bg-container-primary-semi);
|
|
170
|
+
border-color: var(--color-bg-container-border);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.ds-prompt-suggestions__card--pending:hover {
|
|
174
|
+
transform: none;
|
|
175
|
+
box-shadow: none;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.ds-prompt-suggestions__tile:focus-visible,
|
|
179
|
+
.ds-prompt-suggestions__card:focus-visible {
|
|
180
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
181
|
+
outline-offset: 2px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ds-prompt-suggestions__tile {
|
|
185
|
+
gap: var(--gap-300);
|
|
186
|
+
padding: var(--padding-400);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.ds-prompt-suggestions__card {
|
|
190
|
+
gap: var(--gap-200);
|
|
191
|
+
padding: var(--padding-200) var(--padding-200) var(--padding-400);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.ds-prompt-suggestions__text {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: column;
|
|
197
|
+
gap: var(--gap-050);
|
|
198
|
+
min-width: 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.ds-prompt-suggestions__card .ds-prompt-suggestions__text {
|
|
202
|
+
padding-inline: var(--padding-200);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.ds-prompt-suggestions__label {
|
|
206
|
+
font-family: var(--font-paragraph-sm-emphasis-family);
|
|
207
|
+
font-size: var(--font-paragraph-sm-emphasis-size);
|
|
208
|
+
font-weight: var(--font-paragraph-sm-emphasis-weight);
|
|
209
|
+
line-height: var(--font-paragraph-sm-emphasis-line-height);
|
|
210
|
+
letter-spacing: var(--font-paragraph-sm-emphasis-letter-spacing);
|
|
211
|
+
color: var(--color-text-primary);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.ds-prompt-suggestions__description {
|
|
215
|
+
font-family: var(--font-caption-family);
|
|
216
|
+
font-size: var(--font-caption-size);
|
|
217
|
+
font-weight: var(--font-caption-weight);
|
|
218
|
+
line-height: var(--font-caption-line-height);
|
|
219
|
+
letter-spacing: var(--font-caption-letter-spacing);
|
|
220
|
+
color: var(--color-text-tertiary);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ds-prompt-suggestions__icon {
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
--icon-size: var(--icon-size-600);
|
|
226
|
+
color: var(--color-icon-secondary);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* The card's cover: a wash of one pixel ink, strong at the top and nearly
|
|
230
|
+
gone by the floor, with the subject's icon standing in it in the same
|
|
231
|
+
ink. The inks cycle by position, so a row of cards is told apart by
|
|
232
|
+
colour as well as by title, and they are the theme-split set, so the icon
|
|
233
|
+
holds its contrast in both modes. */
|
|
234
|
+
.ds-prompt-suggestions__cover {
|
|
235
|
+
display: flex;
|
|
236
|
+
align-items: center;
|
|
237
|
+
justify-content: center;
|
|
238
|
+
/* Twice the cover icon's own size: the icon scale sets the proportion. */
|
|
239
|
+
height: calc(var(--icon-size-1200) * 2);
|
|
240
|
+
border-radius: var(--radius-400);
|
|
241
|
+
background-image: linear-gradient(
|
|
242
|
+
to bottom,
|
|
243
|
+
color-mix(in srgb, var(--ds-prompt-suggestions-tint) 24%, transparent),
|
|
244
|
+
color-mix(in srgb, var(--ds-prompt-suggestions-tint) 6%, transparent)
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.ds-prompt-suggestions__cover .ds-prompt-suggestions__icon {
|
|
249
|
+
--icon-size: var(--icon-size-1200);
|
|
250
|
+
color: var(--ds-prompt-suggestions-tint);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.ds-prompt-suggestions__item:nth-child(6n + 1) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-4); }
|
|
254
|
+
.ds-prompt-suggestions__item:nth-child(6n + 2) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-1); }
|
|
255
|
+
.ds-prompt-suggestions__item:nth-child(6n + 3) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-2); }
|
|
256
|
+
.ds-prompt-suggestions__item:nth-child(6n + 4) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-5); }
|
|
257
|
+
.ds-prompt-suggestions__item:nth-child(6n + 5) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-6); }
|
|
258
|
+
.ds-prompt-suggestions__item:nth-child(6n) { --ds-prompt-suggestions-tint: var(--color-pixel-ink-3); }
|
|
259
|
+
|
|
260
|
+
/* Pending blocks: the real shell holding the label's bar, so the row keeps
|
|
261
|
+
its height when the suggestions land. */
|
|
262
|
+
.ds-prompt-suggestions__tile--pending,
|
|
263
|
+
.ds-prompt-suggestions__card--pending {
|
|
264
|
+
cursor: default;
|
|
265
|
+
font-size: var(--font-paragraph-sm-emphasis-size);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.ds-prompt-suggestions__tile--pending {
|
|
269
|
+
justify-content: flex-end;
|
|
270
|
+
min-height: calc(
|
|
271
|
+
var(--icon-size-600) + var(--gap-300) + var(--font-paragraph-sm-emphasis-line-height) +
|
|
272
|
+
var(--font-caption-line-height) + 2 * var(--padding-400)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* A pending card stands as tall as the loaded one it holds room for: the
|
|
277
|
+
cover, the label line, and two lines of description (the longest a card's
|
|
278
|
+
question runs at this width), so the row does not grow when they land. */
|
|
279
|
+
.ds-prompt-suggestions__card--pending {
|
|
280
|
+
min-height: calc(
|
|
281
|
+
var(--icon-size-1200) * 2 + var(--gap-200) + var(--font-paragraph-sm-emphasis-line-height) +
|
|
282
|
+
var(--gap-050) + 2 * var(--font-caption-line-height) + var(--padding-200) +
|
|
283
|
+
var(--padding-400) + 2 * var(--border-025)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.ds-prompt-suggestions__card--pending .ds-prompt-suggestions__skeleton-bar {
|
|
288
|
+
margin: var(--padding-150) var(--padding-200);
|
|
289
|
+
width: auto;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* The chosen block takes the same press-and-spring the chips do. */
|
|
293
|
+
.ds-prompt-suggestions__item--chosen .ds-prompt-suggestions__tile,
|
|
294
|
+
.ds-prompt-suggestions__item--chosen .ds-prompt-suggestions__card {
|
|
295
|
+
animation: ds-prompt-suggestions-choose var(--motion-duration-slow) var(--motion-ease-spring);
|
|
296
|
+
}
|
|
297
|
+
|
|
80
298
|
/* ============================================
|
|
81
299
|
ITEMS
|
|
82
300
|
============================================ */
|
|
@@ -5,8 +5,10 @@ export interface PromptSuggestion {
|
|
|
5
5
|
id: string;
|
|
6
6
|
/** The suggestion text shown in the chip. */
|
|
7
7
|
label: string;
|
|
8
|
-
/** Optional leading icon — Material Symbol name (string) or custom element (ReactNode). */
|
|
8
|
+
/** Optional leading icon — Material Symbol name (string) or custom element (ReactNode). In the `cards` layout it stands in the card's cover. */
|
|
9
9
|
icon?: string | React.ReactNode;
|
|
10
|
+
/** A quiet second line under the label, drawn by the `tiles` and `cards` layouts: what the tile leads to, or the full question a card asks. The chip layouts have no room for it and leave it out. */
|
|
11
|
+
description?: string;
|
|
10
12
|
}
|
|
11
13
|
/** Props owned by PromptSuggestions itself — everything else falls through to the root element. */
|
|
12
14
|
type PromptSuggestionsOwnProps = {
|
|
@@ -19,9 +21,14 @@ type PromptSuggestionsOwnProps = {
|
|
|
19
21
|
* sideways behind edge fades. `wrap` runs them across as many lines as
|
|
20
22
|
* they need, for empty-state hero placements. `stack` gives each one its
|
|
21
23
|
* own line, for narrow columns where a wrapped row breaks unevenly and
|
|
22
|
-
* the ragged right edge reads as an accident.
|
|
24
|
+
* the ragged right edge reads as an accident. `tiles` and `cards` leave
|
|
25
|
+
* the chip behind for an empty-state home screen: `tiles` is an even row
|
|
26
|
+
* of quiet blocks, each an icon over a label and its `description`;
|
|
27
|
+
* `cards` gives each suggestion a tinted cover holding its icon, with the
|
|
28
|
+
* label and description beneath. Both fold to fewer columns as their own
|
|
29
|
+
* width narrows.
|
|
23
30
|
*/
|
|
24
|
-
layout?: 'scroll' | 'wrap' | 'stack';
|
|
31
|
+
layout?: 'scroll' | 'wrap' | 'stack' | 'tiles' | 'cards';
|
|
25
32
|
/**
|
|
26
33
|
* Legacy alias for `layout="wrap"`; ignored when `layout` is set.
|
|
27
34
|
* @deprecated Use `layout` instead, which also covers `stack`.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { Chip } from "../Chip/Chip.js";
|
|
5
5
|
import { MOTION_EXIT_SYNC_MS } from "../../tokens/motion.js";
|
|
6
6
|
import "./PromptSuggestions.css";
|
|
7
|
+
import "../../fonts/material-symbols.css";
|
|
7
8
|
const PromptSuggestions = React.forwardRef(
|
|
8
9
|
({
|
|
9
10
|
suggestions,
|
|
@@ -37,6 +38,8 @@ const PromptSuggestions = React.forwardRef(
|
|
|
37
38
|
};
|
|
38
39
|
const arrangement = layout ?? (wrap ? "wrap" : "scroll");
|
|
39
40
|
const chipSize = size === "compact" ? "default" : "large";
|
|
41
|
+
const block = arrangement === "tiles" ? "tile" : arrangement === "cards" ? "card" : null;
|
|
42
|
+
const renderIcon = (icon) => typeof icon === "string" ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon material-symbols-rounded`, "aria-hidden": "true", children: icon }) : /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: icon });
|
|
40
43
|
const classes = [
|
|
41
44
|
baseClass,
|
|
42
45
|
`${baseClass}--${size}`,
|
|
@@ -55,7 +58,13 @@ const PromptSuggestions = React.forwardRef(
|
|
|
55
58
|
"aria-label": ariaLabel,
|
|
56
59
|
"aria-busy": pending || void 0,
|
|
57
60
|
"data-pending": pending || void 0,
|
|
58
|
-
children: pending ? Array.from({ length: pendingCount }, (_, index) => /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: `${baseClass}__item`, children:
|
|
61
|
+
children: pending ? Array.from({ length: pendingCount }, (_, index) => /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: `${baseClass}__item`, children: block ? (
|
|
62
|
+
/* The block's own shell, holding the label's bar. */
|
|
63
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__${block} ${baseClass}__${block}--pending`, children: [
|
|
64
|
+
block === "card" && /* @__PURE__ */ jsx("span", { className: `${baseClass}__cover` }),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__skeleton-bar` })
|
|
66
|
+
] })
|
|
67
|
+
) : /* @__PURE__ */ jsx("span", { className: `${baseClass}__skeleton`, children: /* @__PURE__ */ jsx("span", { className: `${baseClass}__skeleton-bar` }) }) }, index)) : suggestions.map((suggestion) => /* @__PURE__ */ jsx(
|
|
59
68
|
"div",
|
|
60
69
|
{
|
|
61
70
|
role: "listitem",
|
|
@@ -65,7 +74,21 @@ const PromptSuggestions = React.forwardRef(
|
|
|
65
74
|
setChosenId(null);
|
|
66
75
|
}
|
|
67
76
|
},
|
|
68
|
-
children: /* @__PURE__ */
|
|
77
|
+
children: block ? /* @__PURE__ */ jsxs(
|
|
78
|
+
"button",
|
|
79
|
+
{
|
|
80
|
+
type: "button",
|
|
81
|
+
className: `${baseClass}__${block}`,
|
|
82
|
+
onClick: () => choose(suggestion.id),
|
|
83
|
+
children: [
|
|
84
|
+
block === "card" ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__cover`, children: suggestion.icon != null && renderIcon(suggestion.icon) }) : suggestion.icon != null && renderIcon(suggestion.icon),
|
|
85
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__text`, children: [
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: suggestion.label }),
|
|
87
|
+
suggestion.description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__description`, children: suggestion.description })
|
|
88
|
+
] })
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
) : /* @__PURE__ */ jsx(
|
|
69
92
|
Chip,
|
|
70
93
|
{
|
|
71
94
|
label: suggestion.label,
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
|
|
37
37
|
/* ============================================
|
|
38
38
|
VARIANT — PULL (large display quote)
|
|
39
|
-
Display type
|
|
40
|
-
|
|
39
|
+
Display-tier type: no border, the scale is
|
|
40
|
+
the emphasis.
|
|
41
41
|
============================================ */
|
|
42
42
|
|
|
43
43
|
.ds-quote--pull .ds-quote__text {
|
|
@@ -22,7 +22,7 @@ export interface ShaderParams {
|
|
|
22
22
|
/**
|
|
23
23
|
* How much the composition resists shrinking with the container, 0–1.
|
|
24
24
|
*
|
|
25
|
-
* At 0 — the
|
|
25
|
+
* At 0 — the behaviour a CSS blob layer has — the whole
|
|
26
26
|
* field is fitted to whatever width it is given, so a phone shows the
|
|
27
27
|
* entire composition at phone scale: every source small, and more of them
|
|
28
28
|
* crowded into view than the look was built for. At 1 the field holds the
|
|
@@ -31,9 +31,9 @@ export interface ShaderParams {
|
|
|
31
31
|
* keeping some of the shrink so colours still bleed together on a small
|
|
32
32
|
* screen. Above the reference width it does nothing.
|
|
33
33
|
*
|
|
34
|
-
*
|
|
35
|
-
* scene rather than a diagram;
|
|
36
|
-
* the whole composition, such as a small demo tile.
|
|
34
|
+
* The default sits between the two, which suits a full-viewport background,
|
|
35
|
+
* read on a phone as a scene rather than a diagram; set it to 0 wherever
|
|
36
|
+
* the point is to see the whole composition, such as a small demo tile.
|
|
37
37
|
*/
|
|
38
38
|
crop: number;
|
|
39
39
|
}
|
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
/* Layout */
|
|
10
10
|
display: inline-flex;
|
|
11
11
|
align-items: center;
|
|
12
|
-
gap: var(--gap-
|
|
12
|
+
gap: var(--gap-200); /* 8px */
|
|
13
13
|
|
|
14
|
-
/* Spacing
|
|
15
|
-
|
|
14
|
+
/* Spacing — the leading slot is tucked into the pill's start: the same
|
|
15
|
+
inset above, below and before it, so its circle is concentric with the
|
|
16
|
+
pill's end cap. */
|
|
17
|
+
--ds-source-chip-inset: var(--padding-100); /* 4px */
|
|
18
|
+
padding: var(--ds-source-chip-inset);
|
|
19
|
+
padding-inline-end: var(--padding-300); /* 12px */
|
|
16
20
|
|
|
17
21
|
/* Shape — borderless pill on the secondary container */
|
|
18
22
|
border-radius: var(--radius-pill);
|
|
@@ -45,8 +49,14 @@
|
|
|
45
49
|
flex-shrink: 0;
|
|
46
50
|
min-width: var(--icon-size-500);
|
|
47
51
|
height: var(--icon-size-500);
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
/* Concentric with the pill: its radius less the inset between them. A
|
|
53
|
+
squared theme squares the badge with it. */
|
|
54
|
+
border-radius: calc(var(--radius-pill) - var(--ds-source-chip-inset));
|
|
55
|
+
/* A solid inverse disc, so the numeral carries the weight a logo's
|
|
56
|
+
full-colour disc does: dark on light in dark mode, light on dark in
|
|
57
|
+
light mode. It holds through hover and press — the pill's wash moves
|
|
58
|
+
behind it. */
|
|
59
|
+
background-color: var(--color-bg-container-inverse);
|
|
50
60
|
|
|
51
61
|
font-family: var(--font-paragraph-sm-emphasis-family);
|
|
52
62
|
font-size: var(--font-paragraph-sm-emphasis-size);
|
|
@@ -54,7 +64,17 @@
|
|
|
54
64
|
letter-spacing: var(--font-paragraph-sm-emphasis-letter-spacing);
|
|
55
65
|
line-height: 1;
|
|
56
66
|
font-variant-numeric: tabular-nums;
|
|
57
|
-
color: var(--color-text-
|
|
67
|
+
color: var(--color-text-on-inverse);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Centre the digit, not its line box. A line box reserves room for
|
|
71
|
+
descenders a lining figure never uses, so centring the box sets the
|
|
72
|
+
numeral visibly high in a 20px disc. Trimming the box to cap height and
|
|
73
|
+
baseline leaves only the glyph for the disc to centre. Browsers without
|
|
74
|
+
text-box keep the line-box centring. */
|
|
75
|
+
.ds-source-chip__numeral {
|
|
76
|
+
display: block;
|
|
77
|
+
text-box: trim-both cap alphabetic;
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
/* ============================================
|
|
@@ -62,12 +82,45 @@
|
|
|
62
82
|
============================================ */
|
|
63
83
|
|
|
64
84
|
.ds-source-chip__icon {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
65
88
|
flex-shrink: 0;
|
|
89
|
+
width: var(--icon-size-500);
|
|
90
|
+
height: var(--icon-size-500);
|
|
66
91
|
--icon-size: var(--icon-size-500);
|
|
67
92
|
line-height: 1;
|
|
68
93
|
color: var(--color-icon-primary);
|
|
69
94
|
}
|
|
70
95
|
|
|
96
|
+
/* ============================================
|
|
97
|
+
LOGO (leading, when no index; and the
|
|
98
|
+
preview's top line). The source's mark,
|
|
99
|
+
cropped to the badge's shape. An image
|
|
100
|
+
fills the box; a custom element is
|
|
101
|
+
stretched to it. The tertiary ground shows
|
|
102
|
+
through a transparent favicon, so it still
|
|
103
|
+
reads as a badge.
|
|
104
|
+
============================================ */
|
|
105
|
+
|
|
106
|
+
.ds-source-chip__logo {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
flex-shrink: 0;
|
|
111
|
+
width: var(--icon-size-500);
|
|
112
|
+
height: var(--icon-size-500);
|
|
113
|
+
border-radius: calc(var(--radius-pill) - var(--ds-source-chip-inset));
|
|
114
|
+
background-color: var(--color-bg-container-tertiary);
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ds-source-chip__logo > * {
|
|
119
|
+
width: 100%;
|
|
120
|
+
height: 100%;
|
|
121
|
+
object-fit: cover;
|
|
122
|
+
}
|
|
123
|
+
|
|
71
124
|
/* ============================================
|
|
72
125
|
TITLE — truncates with an ellipsis
|
|
73
126
|
============================================ */
|
|
@@ -80,15 +133,31 @@
|
|
|
80
133
|
}
|
|
81
134
|
|
|
82
135
|
/* ============================================
|
|
83
|
-
|
|
136
|
+
INTERACTIVE (rendered as <a> or <button>)
|
|
137
|
+
The passive wash, as on Chip: one step on
|
|
138
|
+
hover, one more while pressed. A chip whose
|
|
139
|
+
preview is showing holds the hover step.
|
|
84
140
|
============================================ */
|
|
85
141
|
|
|
86
|
-
.ds-source-chip--
|
|
142
|
+
.ds-source-chip--interactive {
|
|
87
143
|
cursor: pointer;
|
|
88
144
|
}
|
|
89
145
|
|
|
90
|
-
|
|
91
|
-
|
|
146
|
+
/* The <button> form: clear the UA chrome the anchor never had. */
|
|
147
|
+
button.ds-source-chip {
|
|
148
|
+
border: 0;
|
|
149
|
+
margin: 0;
|
|
150
|
+
appearance: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.ds-source-chip--interactive:hover,
|
|
154
|
+
.ds-source-chip--open {
|
|
155
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
156
|
+
color: var(--color-text-primary);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ds-source-chip--interactive:active {
|
|
160
|
+
background-color: var(--color-action-passive-bg-active);
|
|
92
161
|
color: var(--color-text-primary);
|
|
93
162
|
}
|
|
94
163
|
|
|
@@ -96,11 +165,142 @@
|
|
|
96
165
|
FOCUS
|
|
97
166
|
============================================ */
|
|
98
167
|
|
|
99
|
-
.ds-source-chip--
|
|
168
|
+
.ds-source-chip--interactive:focus-visible {
|
|
100
169
|
outline: 2px solid var(--color-action-primary-bg);
|
|
101
170
|
outline-offset: 2px;
|
|
102
171
|
}
|
|
103
172
|
|
|
173
|
+
/* ============================================
|
|
174
|
+
PREVIEW
|
|
175
|
+
The source behind the chip, on the floating
|
|
176
|
+
surface (see HoverCard). The host is the
|
|
177
|
+
positioning box; the panel opens above the
|
|
178
|
+
chip, flush with its leading edge. The
|
|
179
|
+
component flips it below (data-side) and
|
|
180
|
+
slides it sideways (--ds-source-chip-shift)
|
|
181
|
+
when the space runs out.
|
|
182
|
+
============================================ */
|
|
183
|
+
|
|
184
|
+
.ds-source-chip-host {
|
|
185
|
+
position: relative;
|
|
186
|
+
display: inline-flex;
|
|
187
|
+
min-width: 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.ds-source-chip__preview {
|
|
191
|
+
position: absolute;
|
|
192
|
+
z-index: 50;
|
|
193
|
+
bottom: 100%;
|
|
194
|
+
left: var(--ds-source-chip-shift, 0px);
|
|
195
|
+
margin-block: var(--gap-200);
|
|
196
|
+
width: max-content;
|
|
197
|
+
max-width: min(320px, calc(100vw - var(--padding-400)));
|
|
198
|
+
padding: var(--padding-300) var(--padding-400);
|
|
199
|
+
flex-direction: column;
|
|
200
|
+
gap: var(--gap-100);
|
|
201
|
+
|
|
202
|
+
border-radius: var(--radius-300);
|
|
203
|
+
background-color: var(--color-bg-page-primary);
|
|
204
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
205
|
+
box-shadow: var(--shadow-floating);
|
|
206
|
+
|
|
207
|
+
font-family: var(--font-paragraph-sm-family);
|
|
208
|
+
font-size: var(--font-paragraph-sm-size);
|
|
209
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
210
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
211
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
212
|
+
color: var(--color-text-secondary);
|
|
213
|
+
text-align: start;
|
|
214
|
+
white-space: normal;
|
|
215
|
+
cursor: default;
|
|
216
|
+
|
|
217
|
+
/* display:none keeps the closed panel out of the tab order and the page's
|
|
218
|
+
scrollable overflow; the flip transitions discretely so the fade
|
|
219
|
+
survives (see HoverCard, which owns the explanation). */
|
|
220
|
+
display: none;
|
|
221
|
+
opacity: 0;
|
|
222
|
+
transform: translateY(4px);
|
|
223
|
+
transition-property: opacity, transform, display;
|
|
224
|
+
transition-duration: var(--motion-duration-fast);
|
|
225
|
+
transition-timing-function: var(--motion-ease-standard);
|
|
226
|
+
transition-behavior: allow-discrete;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.ds-source-chip__preview[data-side='bottom'] {
|
|
230
|
+
top: 100%;
|
|
231
|
+
bottom: auto;
|
|
232
|
+
transform: translateY(-4px);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.ds-source-chip__preview--visible,
|
|
236
|
+
.ds-source-chip__preview--visible[data-side='bottom'] {
|
|
237
|
+
display: flex;
|
|
238
|
+
opacity: 1;
|
|
239
|
+
transform: translateY(0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@starting-style {
|
|
243
|
+
.ds-source-chip__preview--visible {
|
|
244
|
+
opacity: 0;
|
|
245
|
+
transform: translateY(4px);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.ds-source-chip__preview--visible[data-side='bottom'] {
|
|
249
|
+
opacity: 0;
|
|
250
|
+
transform: translateY(-4px);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* Top line: where the source lives, a trailing fact, and the outbound
|
|
255
|
+
arrow when the chip is a link. */
|
|
256
|
+
.ds-source-chip__preview-top {
|
|
257
|
+
display: flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
gap: var(--gap-200);
|
|
260
|
+
color: var(--color-text-tertiary);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.ds-source-chip__preview-source {
|
|
264
|
+
min-width: 0;
|
|
265
|
+
overflow: hidden;
|
|
266
|
+
white-space: nowrap;
|
|
267
|
+
text-overflow: ellipsis;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.ds-source-chip__preview-meta {
|
|
271
|
+
flex-shrink: 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* A middle dot between the two, drawn only when both are present. */
|
|
275
|
+
.ds-source-chip__preview-source + .ds-source-chip__preview-meta::before {
|
|
276
|
+
content: '\00B7';
|
|
277
|
+
margin-inline-end: var(--gap-200);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.ds-source-chip__preview-open {
|
|
281
|
+
flex-shrink: 0;
|
|
282
|
+
margin-inline-start: auto;
|
|
283
|
+
--icon-size: var(--icon-size-500);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.ds-source-chip__preview-title {
|
|
287
|
+
font-family: var(--font-paragraph-sm-emphasis-family);
|
|
288
|
+
font-size: var(--font-paragraph-sm-emphasis-size);
|
|
289
|
+
font-weight: var(--font-paragraph-sm-emphasis-weight);
|
|
290
|
+
line-height: var(--font-paragraph-sm-emphasis-line-height);
|
|
291
|
+
letter-spacing: var(--font-paragraph-sm-emphasis-letter-spacing);
|
|
292
|
+
color: var(--color-text-primary);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* The excerpt is a glance, not the document: four lines, then an ellipsis. */
|
|
296
|
+
.ds-source-chip__preview-excerpt {
|
|
297
|
+
display: -webkit-box;
|
|
298
|
+
-webkit-box-orient: vertical;
|
|
299
|
+
-webkit-line-clamp: 4;
|
|
300
|
+
line-clamp: 4;
|
|
301
|
+
overflow: hidden;
|
|
302
|
+
}
|
|
303
|
+
|
|
104
304
|
/* Icons take the colour of the text around them. Explicit, not just
|
|
105
305
|
inherited by default: a consumer stylesheet that sets a colour on
|
|
106
306
|
.material-symbols-rounded itself (a common global default) would
|