rift-ds 1.15.0 → 1.17.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/bin/templates/blocks/components/blocks/AppShell.tsx +1 -1
- package/chat/ChatLauncher.d.ts +11 -1
- package/chat/ChatLauncher.js +7 -1
- package/chat/ChatWidget.css +21 -0
- package/components/AppLayout/AppLayout.css +90 -2
- package/components/AppLayout/AppLayout.d.ts +10 -2
- package/components/AppLayout/AppLayout.js +20 -2
- package/components/AppSidebar/AppSidebar.css +26 -0
- package/components/AppSidebar/AppSidebar.d.ts +15 -4
- package/components/AppSidebar/AppSidebar.js +7 -2
- package/components/Checkbox/Checkbox.css +4 -2
- package/components/DataTable/DataTable.js +29 -9
- package/components/DataTable/FilterEditor.js +1 -2
- package/components/DataTable/filterModel.js +4 -3
- package/components/DataTable/views.d.ts +9 -0
- package/components/DataTable/views.js +10 -1
- package/components/Drawer/Drawer.d.ts +6 -0
- package/components/Drawer/Drawer.js +11 -1
- package/components/MegaMenu/MegaMenu.css +271 -0
- package/components/MegaMenu/MegaMenu.d.ts +72 -0
- package/components/MegaMenu/MegaMenu.js +71 -0
- package/components/Nav/Nav.d.ts +7 -2
- package/components/ProgressiveBlur/ProgressiveBlur.css +102 -0
- package/components/ProgressiveBlur/ProgressiveBlur.d.ts +30 -0
- package/components/ProgressiveBlur/ProgressiveBlur.js +27 -0
- package/components/PromptSuggestions/PromptSuggestions.css +1 -1
- package/components/QuestionCard/QuestionCard.css +3 -2
- package/components/QuestionCard/QuestionCard.js +2 -8
- package/components/RadioButton/RadioButton.css +5 -3
- package/components/SegmentedControl/SegmentedControl.css +69 -0
- package/components/SegmentedControl/SegmentedControl.d.ts +4 -3
- package/components/SegmentedControl/SegmentedControl.js +90 -48
- package/components/SiteHeader/SiteHeader.css +305 -0
- package/components/SiteHeader/SiteHeader.d.ts +117 -0
- package/components/SiteHeader/SiteHeader.js +329 -0
- package/components/TableToolbar/TableToolbar.css +6 -0
- package/components/TableToolbar/TableToolbar.js +52 -16
- package/components/ThemeToggle/ThemeToggle.css +2 -72
- package/components/ThemeToggle/ThemeToggle.d.ts +1 -1
- package/components/ThemeToggle/ThemeToggle.js +4 -40
- package/components/registry.json +26 -2
- package/components/registry.json.d.ts +26 -2
- package/components/registry.json.js +1 -1
- package/index.d.ts +3 -0
- package/index.js +6 -0
- package/package.json +1 -1
- package/tokens/registry.json +3 -0
- package/tokens/registry.json.d.ts +3 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +8 -0
- package/tokens/tokens-light.css +8 -0
|
@@ -5,6 +5,7 @@ import { CircularButton } from "../CircularButton/CircularButton.js";
|
|
|
5
5
|
import ReactDOM from "react-dom";
|
|
6
6
|
import "./Drawer.css";
|
|
7
7
|
import "../../behaviors/direction.css";
|
|
8
|
+
import "../../behaviors/visually-hidden.css";
|
|
8
9
|
import "../../fonts/material-symbols.css";
|
|
9
10
|
import { useMounted } from "../../behaviors/useMounted.js";
|
|
10
11
|
import { useLayer } from "../../behaviors/useLayer.js";
|
|
@@ -16,6 +17,7 @@ const Drawer = React.forwardRef(
|
|
|
16
17
|
onOpenChange,
|
|
17
18
|
title,
|
|
18
19
|
description,
|
|
20
|
+
heading,
|
|
19
21
|
children,
|
|
20
22
|
footer,
|
|
21
23
|
side = "right",
|
|
@@ -65,7 +67,15 @@ const Drawer = React.forwardRef(
|
|
|
65
67
|
children: [
|
|
66
68
|
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__header`, children: [
|
|
67
69
|
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__heading`, children: [
|
|
68
|
-
/* @__PURE__ */ jsx(
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"h2",
|
|
72
|
+
{
|
|
73
|
+
className: heading ? "ds-visually-hidden" : `${baseClass}__title`,
|
|
74
|
+
id: titleId,
|
|
75
|
+
children: title
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
heading,
|
|
69
79
|
description && /* @__PURE__ */ jsx("p", { className: `${baseClass}__description`, id: descId, children: description })
|
|
70
80
|
] }),
|
|
71
81
|
dismissible && /* @__PURE__ */ jsx(
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
MEGA MENU
|
|
3
|
+
A wide navigation panel: icon rows plus an
|
|
4
|
+
optional featured card
|
|
5
|
+
============================================ */
|
|
6
|
+
|
|
7
|
+
/* Base: the floating glass shell, CommandPalette's surface. The panel is a
|
|
8
|
+
shallow strip that lands on whatever the page opens with, display type
|
|
9
|
+
most of it, so its blur runs harder than the shell's 24px: at that
|
|
10
|
+
strength a heading that size still reads through the row labels. */
|
|
11
|
+
.ds-mega-menu {
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
padding: var(--padding-1000);
|
|
14
|
+
background-color: var(--color-bg-glass);
|
|
15
|
+
backdrop-filter: blur(32px);
|
|
16
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
17
|
+
border-radius: var(--radius-400);
|
|
18
|
+
box-shadow: var(--shadow-floating);
|
|
19
|
+
/* The showcase card's height floor is sized against this box. */
|
|
20
|
+
container: ds-mega-menu / inline-size;
|
|
21
|
+
|
|
22
|
+
/* Closed: faded out, then hidden once the fade has run, so a reopen
|
|
23
|
+
mid-fade picks up where it was. */
|
|
24
|
+
opacity: 0;
|
|
25
|
+
visibility: hidden;
|
|
26
|
+
transition:
|
|
27
|
+
opacity var(--motion-duration-base) var(--motion-ease-standard),
|
|
28
|
+
visibility 0s linear var(--motion-duration-base);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* States */
|
|
32
|
+
.ds-mega-menu--open {
|
|
33
|
+
opacity: 1;
|
|
34
|
+
visibility: visible;
|
|
35
|
+
transition: opacity var(--motion-duration-base) var(--motion-ease-standard);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Layout: the link grid alone, or the grid in two thirds beside the
|
|
39
|
+
showcase in one. */
|
|
40
|
+
.ds-mega-menu__layout {
|
|
41
|
+
display: grid;
|
|
42
|
+
grid-template-columns: minmax(0, 1fr);
|
|
43
|
+
gap: var(--gap-1000);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ds-mega-menu__layout--showcase {
|
|
47
|
+
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* The link grid: four rows to a column, wrapping into further columns, so
|
|
51
|
+
a long menu grows sideways and never into a scroll. */
|
|
52
|
+
.ds-mega-menu__grid {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-rows: repeat(4, auto);
|
|
55
|
+
grid-auto-flow: column;
|
|
56
|
+
grid-auto-columns: minmax(0, 1fr);
|
|
57
|
+
gap: var(--gap-200) var(--gap-1000);
|
|
58
|
+
align-content: start;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Rows: the overlay row family. No fill at rest, the passive wash on hover
|
|
62
|
+
and focus at --radius-200, and the navigation current item one step past
|
|
63
|
+
it, so current and hovered never read the same. */
|
|
64
|
+
.ds-mega-menu__item {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: flex-start;
|
|
67
|
+
gap: var(--gap-300);
|
|
68
|
+
min-width: 0;
|
|
69
|
+
padding: var(--padding-300) var(--padding-400);
|
|
70
|
+
border-radius: var(--radius-200);
|
|
71
|
+
color: inherit;
|
|
72
|
+
text-decoration: none;
|
|
73
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.ds-mega-menu__item:hover {
|
|
77
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ds-mega-menu__item:focus-visible {
|
|
81
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
82
|
+
outline-offset: 2px;
|
|
83
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.ds-mega-menu__item--current {
|
|
87
|
+
background-color: var(--color-action-passive-bg-active);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* The icon tile: a step of container fill around the glyph, holding that
|
|
91
|
+
step over the row's hover wash. Its corner is the row's own radius, since
|
|
92
|
+
the tile sits at the row's start with no padding between them on that
|
|
93
|
+
axis that would ask for a smaller one. */
|
|
94
|
+
.ds-mega-menu__icon {
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
width: calc(var(--icon-size-600) + var(--padding-200) * 2);
|
|
100
|
+
height: calc(var(--icon-size-600) + var(--padding-200) * 2);
|
|
101
|
+
border-radius: var(--radius-200);
|
|
102
|
+
background-color: var(--color-bg-container-secondary);
|
|
103
|
+
color: var(--color-text-primary);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* The tile keeps a step of contrast when the row behind it fills in. The
|
|
107
|
+
hover wash already differs from the tile's resting fill; the current
|
|
108
|
+
row's wash is that same fill, so there the tile takes the other step. */
|
|
109
|
+
.ds-mega-menu__item--current .ds-mega-menu__icon {
|
|
110
|
+
background-color: var(--color-bg-container-tertiary);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ds-mega-menu__icon .material-symbols-rounded {
|
|
114
|
+
--icon-size: var(--icon-size-600);
|
|
115
|
+
line-height: 1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ds-mega-menu__logo {
|
|
119
|
+
display: block;
|
|
120
|
+
width: var(--icon-size-600);
|
|
121
|
+
height: var(--icon-size-600);
|
|
122
|
+
object-fit: contain;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ds-mega-menu__text {
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-direction: column;
|
|
128
|
+
gap: var(--gap-100);
|
|
129
|
+
min-width: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.ds-mega-menu__label {
|
|
133
|
+
font-family: var(--font-title-body-family);
|
|
134
|
+
font-size: var(--font-title-body-size);
|
|
135
|
+
font-weight: var(--font-title-body-weight);
|
|
136
|
+
line-height: var(--font-title-body-line-height);
|
|
137
|
+
letter-spacing: var(--font-title-body-letter-spacing);
|
|
138
|
+
color: var(--color-text-primary);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Rows stay even: a description is at most two lines. The full sentence
|
|
142
|
+
lives on the page the row links to. */
|
|
143
|
+
.ds-mega-menu__description {
|
|
144
|
+
display: -webkit-box;
|
|
145
|
+
-webkit-line-clamp: 2;
|
|
146
|
+
-webkit-box-orient: vertical;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
font-family: var(--font-paragraph-sm-family);
|
|
149
|
+
font-size: var(--font-paragraph-sm-size);
|
|
150
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
151
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
152
|
+
color: var(--color-text-tertiary);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Showcase: the column carries the divider, the card fills it. */
|
|
156
|
+
.ds-mega-menu__showcase-column {
|
|
157
|
+
display: flex;
|
|
158
|
+
padding-inline-start: var(--padding-1000);
|
|
159
|
+
border-inline-start: var(--border-025) solid var(--color-bg-container-border);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* One link that is the whole card. The cover fills it and absorbs whatever
|
|
163
|
+
height the link grid runs to, so the columns always bottom-align; the
|
|
164
|
+
floor keeps a short grid's card at about 4:3 so the drawing has room
|
|
165
|
+
above the copy. */
|
|
166
|
+
.ds-mega-menu__showcase {
|
|
167
|
+
position: relative;
|
|
168
|
+
flex: 1;
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
justify-content: flex-end;
|
|
172
|
+
min-width: 0;
|
|
173
|
+
min-height: 25cqw;
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
176
|
+
border-radius: var(--radius-300);
|
|
177
|
+
color: inherit;
|
|
178
|
+
text-decoration: none;
|
|
179
|
+
transition: border-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.ds-mega-menu__showcase:hover {
|
|
183
|
+
border-color: var(--color-bg-container-tertiary);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.ds-mega-menu__showcase:focus-visible {
|
|
187
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
188
|
+
outline-offset: 4px;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* The cover's gentle zoom on hover is the card acknowledging the pointer,
|
|
192
|
+
clipped by the frame. */
|
|
193
|
+
.ds-mega-menu__cover {
|
|
194
|
+
position: absolute;
|
|
195
|
+
inset: 0;
|
|
196
|
+
transition: scale var(--motion-duration-fast) var(--motion-ease-standard);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.ds-mega-menu__cover > * {
|
|
200
|
+
width: 100%;
|
|
201
|
+
height: 100%;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.ds-mega-menu__showcase:hover .ds-mega-menu__cover {
|
|
205
|
+
scale: 1.02;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* The copy, kept legible on the drawing by a rise of page surface from the
|
|
209
|
+
card's foot. The tall top padding is the fade zone; the text never
|
|
210
|
+
reaches it. */
|
|
211
|
+
.ds-mega-menu__showcase-text {
|
|
212
|
+
position: relative;
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-direction: column;
|
|
215
|
+
gap: var(--gap-100);
|
|
216
|
+
padding: var(--padding-1500) var(--padding-500) var(--padding-500);
|
|
217
|
+
/* ds-allow(color): the transparent end of the fade, not a palette colour */
|
|
218
|
+
background: linear-gradient(to top, var(--color-bg-page-primary) 55%, transparent);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.ds-mega-menu__overline {
|
|
222
|
+
font-family: var(--font-overline-family);
|
|
223
|
+
font-size: var(--font-overline-size);
|
|
224
|
+
font-weight: var(--font-overline-weight);
|
|
225
|
+
line-height: var(--font-overline-line-height);
|
|
226
|
+
letter-spacing: var(--font-overline-letter-spacing);
|
|
227
|
+
text-transform: uppercase;
|
|
228
|
+
color: var(--color-text-tertiary);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.ds-mega-menu__showcase-title {
|
|
232
|
+
display: flex;
|
|
233
|
+
align-items: center;
|
|
234
|
+
gap: var(--gap-100);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.ds-mega-menu__arrow {
|
|
238
|
+
--icon-size: var(--icon-size-500);
|
|
239
|
+
line-height: 1;
|
|
240
|
+
color: var(--color-action-passive-text);
|
|
241
|
+
transition: translate var(--motion-duration-fast) var(--motion-ease-standard);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.ds-mega-menu__showcase:hover .ds-mega-menu__arrow {
|
|
245
|
+
translate: calc(var(--gap-050) * var(--ds-inline-sign, 1)) 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Narrow: a panel without the room for two column groups stacks the
|
|
249
|
+
showcase under the grid and lets the grid run one column deep.
|
|
250
|
+
ds-allow(breakpoint): content-driven: two row columns and the showcase need about 720px of panel. */
|
|
251
|
+
@container ds-mega-menu (max-width: 720px) {
|
|
252
|
+
.ds-mega-menu__layout--showcase {
|
|
253
|
+
grid-template-columns: minmax(0, 1fr);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.ds-mega-menu__grid {
|
|
257
|
+
grid-template-rows: none;
|
|
258
|
+
grid-auto-flow: row;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.ds-mega-menu__showcase-column {
|
|
262
|
+
padding-inline-start: 0;
|
|
263
|
+
border-inline-start: none;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* Full width now, so the floor that kept a third-width card at 4:3
|
|
267
|
+
becomes a wide band with the same room above the copy. */
|
|
268
|
+
.ds-mega-menu__showcase {
|
|
269
|
+
min-height: 50cqw;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { LinkComponent } from '../../behaviors/LinkProvider';
|
|
3
|
+
/** One link row in a mega menu: a page and the line that says what is on it. */
|
|
4
|
+
export interface MegaMenuItem {
|
|
5
|
+
/** Where the row links. */
|
|
6
|
+
href: string;
|
|
7
|
+
/** The page's name. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** One line on what the page holds, clamped to two lines in the panel. */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** A Material Symbols name drawn in the row's icon tile. */
|
|
12
|
+
icon?: string;
|
|
13
|
+
/** An image path drawn in the icon tile instead of `icon`, for a brand or product mark. */
|
|
14
|
+
logo?: string;
|
|
15
|
+
}
|
|
16
|
+
/** The featured card beside a mega menu's link grid: one link that is the whole card. */
|
|
17
|
+
export interface MegaMenuShowcase {
|
|
18
|
+
/** Where the card links. */
|
|
19
|
+
href: string;
|
|
20
|
+
/** A short kicker above the title, set in the overline face. */
|
|
21
|
+
overline?: string;
|
|
22
|
+
/** The card's title, followed by a forward arrow. */
|
|
23
|
+
label: string;
|
|
24
|
+
/** One or two lines under the title. */
|
|
25
|
+
description?: string;
|
|
26
|
+
/**
|
|
27
|
+
* A drawing that fills the card behind the copy. Decorative: the title and
|
|
28
|
+
* description carry the meaning, so mark it `aria-hidden`.
|
|
29
|
+
*/
|
|
30
|
+
cover?: React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
/** Props owned by MegaMenu itself — everything else falls through to the panel `<div>`. */
|
|
33
|
+
type MegaMenuOwnProps = {
|
|
34
|
+
/**
|
|
35
|
+
* Whether the panel shows. Controlled by design: the host owns the
|
|
36
|
+
* triggers that open it, so it owns this state too. A closed panel fades
|
|
37
|
+
* out and is `inert`, so its links leave the tab order.
|
|
38
|
+
*/
|
|
39
|
+
open: boolean;
|
|
40
|
+
/** The link rows, laid out four to a column and wrapping into further columns. */
|
|
41
|
+
items: MegaMenuItem[];
|
|
42
|
+
/** A featured card in its own column beside the link grid. */
|
|
43
|
+
showcase?: MegaMenuShowcase;
|
|
44
|
+
/**
|
|
45
|
+
* The path of the page being viewed. A row whose `href` is this path, or a
|
|
46
|
+
* parent of it, is marked as the current page.
|
|
47
|
+
*/
|
|
48
|
+
currentHref?: string;
|
|
49
|
+
/** Called when any link in the panel is followed, so a host can close it. */
|
|
50
|
+
onNavigate?: () => void;
|
|
51
|
+
/**
|
|
52
|
+
* The component every link renders through, so a router's link (Next.js
|
|
53
|
+
* `Link`) navigates without a reload. The panel is server-renderable, so it
|
|
54
|
+
* cannot read a `LinkProvider`; a client host resolves one and passes it
|
|
55
|
+
* here. Defaults to `<a>`.
|
|
56
|
+
*/
|
|
57
|
+
linkComponent?: LinkComponent;
|
|
58
|
+
/** Additional CSS classes on the panel. */
|
|
59
|
+
className?: string;
|
|
60
|
+
};
|
|
61
|
+
export interface MegaMenuProps extends MegaMenuOwnProps, Omit<React.ComponentPropsWithRef<'div'>, keyof MegaMenuOwnProps> {
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A wide navigation panel: a grid of icon rows, each a page with a line of
|
|
65
|
+
* description, and an optional featured card in a column of its own. It is
|
|
66
|
+
* the panel only. The host places it (under a header bar, usually) and owns
|
|
67
|
+
* the triggers, the hover delay and the dismissal; SiteHeader is the
|
|
68
|
+
* reference host. The forwarded ref and any unrecognised props target the
|
|
69
|
+
* panel `<div>`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function MegaMenu({ open, items, showcase, currentHref, onNavigate, linkComponent, className, ref, ...rest }: MegaMenuProps): React.JSX.Element;
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { mirrorClass } from "../../behaviors/direction.js";
|
|
4
|
+
import "./MegaMenu.css";
|
|
5
|
+
import "../../fonts/material-symbols.css";
|
|
6
|
+
import "../../behaviors/direction.css";
|
|
7
|
+
const isCurrent = (href, currentHref) => currentHref != null && (currentHref === href || currentHref.startsWith(`${href}/`));
|
|
8
|
+
function MegaMenu({
|
|
9
|
+
open,
|
|
10
|
+
items,
|
|
11
|
+
showcase,
|
|
12
|
+
currentHref,
|
|
13
|
+
onNavigate,
|
|
14
|
+
linkComponent,
|
|
15
|
+
className = "",
|
|
16
|
+
ref,
|
|
17
|
+
...rest
|
|
18
|
+
}) {
|
|
19
|
+
const Link = linkComponent ?? "a";
|
|
20
|
+
const baseClass = "ds-mega-menu";
|
|
21
|
+
const classes = [baseClass, open && `${baseClass}--open`, className].filter(Boolean).join(" ");
|
|
22
|
+
return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes, inert: !open, children: /* @__PURE__ */ jsxs(
|
|
23
|
+
"div",
|
|
24
|
+
{
|
|
25
|
+
className: [`${baseClass}__layout`, showcase && `${baseClass}__layout--showcase`].filter(Boolean).join(" "),
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__grid`, children: items.map((item) => {
|
|
28
|
+
const current = isCurrent(item.href, currentHref);
|
|
29
|
+
return /* @__PURE__ */ jsxs(
|
|
30
|
+
Link,
|
|
31
|
+
{
|
|
32
|
+
href: item.href,
|
|
33
|
+
className: [`${baseClass}__item`, current && `${baseClass}__item--current`].filter(Boolean).join(" "),
|
|
34
|
+
"aria-current": current ? "page" : void 0,
|
|
35
|
+
onClick: onNavigate,
|
|
36
|
+
children: [
|
|
37
|
+
(item.logo || item.icon) && /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: item.logo ? /* @__PURE__ */ jsx("img", { className: `${baseClass}__logo`, src: item.logo, alt: "" }) : /* @__PURE__ */ jsx("span", { className: `material-symbols-rounded ${mirrorClass(item.icon)}`, children: item.icon }) }),
|
|
38
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__text`, children: [
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: item.label }),
|
|
40
|
+
item.description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__description`, children: item.description })
|
|
41
|
+
] })
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
item.href
|
|
45
|
+
);
|
|
46
|
+
}) }),
|
|
47
|
+
showcase && /* @__PURE__ */ jsx("div", { className: `${baseClass}__showcase-column`, children: /* @__PURE__ */ jsxs(Link, { href: showcase.href, className: `${baseClass}__showcase`, onClick: onNavigate, children: [
|
|
48
|
+
showcase.cover && /* @__PURE__ */ jsx("span", { className: `${baseClass}__cover`, children: showcase.cover }),
|
|
49
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__showcase-text`, children: [
|
|
50
|
+
showcase.overline && /* @__PURE__ */ jsx("span", { className: `${baseClass}__overline`, children: showcase.overline }),
|
|
51
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__label ${baseClass}__showcase-title`, children: [
|
|
52
|
+
showcase.label,
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"span",
|
|
55
|
+
{
|
|
56
|
+
className: `material-symbols-rounded ds-mirror-rtl ${baseClass}__arrow`,
|
|
57
|
+
"aria-hidden": "true",
|
|
58
|
+
children: "arrow_forward"
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
] }),
|
|
62
|
+
showcase.description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__description`, children: showcase.description })
|
|
63
|
+
] })
|
|
64
|
+
] }) })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
) });
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
MegaMenu
|
|
71
|
+
};
|
package/components/Nav/Nav.d.ts
CHANGED
|
@@ -16,12 +16,17 @@ type NavOwnProps = {
|
|
|
16
16
|
export interface NavProps extends NavOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof NavOwnProps> {
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Nav
|
|
20
|
-
*
|
|
19
|
+
* Nav is the earlier plain top bar: a brand slot and a horizontal
|
|
20
|
+
* ButtonGroup of page links, with no menus and no mobile behaviour of its
|
|
21
|
+
* own. It keeps working for existing consumers, and new work uses
|
|
22
|
+
* SiteHeader, which adds section mega menus, the sticky progressive blur and
|
|
23
|
+
* the fold to a drawer.
|
|
21
24
|
*
|
|
22
25
|
* The landmark is labelled "Main" by default so assistive tech can tell it
|
|
23
26
|
* apart from any other navigation on the page; pass `aria-label` to name it
|
|
24
27
|
* differently. The forwarded ref and any unrecognised props target the `<nav>`.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use `SiteHeader` instead.
|
|
25
30
|
*/
|
|
26
31
|
export declare const Nav: React.ForwardRefExoticComponent<NavProps & React.RefAttributes<HTMLElement>>;
|
|
27
32
|
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
PROGRESSIVE BLUR
|
|
3
|
+
A backdrop blur that dissolves along one edge
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
/* Why a stack, and why masks: a single backdrop-filter is uniform across its
|
|
7
|
+
whole box, so a tint that fades to transparent still ends in a hard line
|
|
8
|
+
where the blur stops. A mask-image multiplies both the layer's paint and
|
|
9
|
+
its filtered backdrop by its alpha, so the blur itself dissolves. Four
|
|
10
|
+
layers with rising blur strength and a shrinking mask band give a
|
|
11
|
+
progressive blur: frosted at the anchored edge, clear at the far one.
|
|
12
|
+
|
|
13
|
+
The blur sits on child layers, never on the root: a backdrop-filter on an
|
|
14
|
+
ancestor would make it a backdrop root, and any glass inside the host
|
|
15
|
+
(a menu panel, say) would then sample only that subtree instead of the
|
|
16
|
+
page. So the host keeps its own children above this element, and the
|
|
17
|
+
blur reads the page behind both.
|
|
18
|
+
|
|
19
|
+
No hand-written -webkit- twins for backdrop-filter: the build's CSS
|
|
20
|
+
pipeline adds the prefix, and a manual one beside it has made the
|
|
21
|
+
pipeline drop the property entirely. */
|
|
22
|
+
|
|
23
|
+
/* Base */
|
|
24
|
+
.ds-progressive-blur {
|
|
25
|
+
/* The tint's colour. An override hook: a host over a different surface
|
|
26
|
+
points it at that surface. */
|
|
27
|
+
--ds-progressive-blur-tint: var(--color-bg-page-primary);
|
|
28
|
+
position: absolute;
|
|
29
|
+
inset: 0;
|
|
30
|
+
/* A child's backdrop-filter is not reliably clipped by a rounded
|
|
31
|
+
overflow: hidden parent, so the frost would show square at the host's
|
|
32
|
+
corners. The root and every layer take the host's corner instead. */
|
|
33
|
+
border-radius: inherit;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ds-progressive-blur--top {
|
|
38
|
+
--ds-progressive-blur-toward: to bottom;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.ds-progressive-blur--bottom {
|
|
42
|
+
--ds-progressive-blur-toward: to top;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ds-progressive-blur__layer {
|
|
46
|
+
position: absolute;
|
|
47
|
+
inset: 0;
|
|
48
|
+
display: block;
|
|
49
|
+
border-radius: inherit;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Layers: blur strength rises as the masked band shrinks, so the edge is
|
|
53
|
+
fully frosted and the far side is sharp. The radii are the effect's own
|
|
54
|
+
tuning, not a scale: a blur radius is not spacing. */
|
|
55
|
+
|
|
56
|
+
/* ds-allow(color): mask alpha keywords (black/transparent), not palette colours */
|
|
57
|
+
|
|
58
|
+
.ds-progressive-blur__layer:nth-child(1) {
|
|
59
|
+
backdrop-filter: blur(2px);
|
|
60
|
+
mask-image: linear-gradient(var(--ds-progressive-blur-toward), black 0%, black 55%, transparent 100%);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-progressive-blur__layer:nth-child(2) {
|
|
64
|
+
backdrop-filter: blur(6px);
|
|
65
|
+
mask-image: linear-gradient(var(--ds-progressive-blur-toward), black 0%, black 40%, transparent 80%);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ds-progressive-blur__layer:nth-child(3) {
|
|
69
|
+
backdrop-filter: blur(12px);
|
|
70
|
+
mask-image: linear-gradient(var(--ds-progressive-blur-toward), black 0%, black 25%, transparent 60%);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ds-progressive-blur__layer:nth-child(4) {
|
|
74
|
+
backdrop-filter: blur(24px);
|
|
75
|
+
mask-image: linear-gradient(var(--ds-progressive-blur-toward), black 0%, black 10%, transparent 40%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Tint: the page surface at the edge stepping to transparent, on its own
|
|
79
|
+
layer above the blur. Only this layer ever fades: transitioning opacity
|
|
80
|
+
on a backdrop-filter makes the browser re-rasterise the blur, which then
|
|
81
|
+
snaps in at the end of the fade, while a plain gradient fades smoothly. */
|
|
82
|
+
.ds-progressive-blur::after {
|
|
83
|
+
content: "";
|
|
84
|
+
position: absolute;
|
|
85
|
+
inset: 0;
|
|
86
|
+
border-radius: inherit;
|
|
87
|
+
background: linear-gradient(
|
|
88
|
+
var(--ds-progressive-blur-toward),
|
|
89
|
+
var(--ds-progressive-blur-tint) 0%,
|
|
90
|
+
color-mix(in srgb, var(--ds-progressive-blur-tint) 90%, transparent) 30%,
|
|
91
|
+
color-mix(in srgb, var(--ds-progressive-blur-tint) 40%, transparent) 65%,
|
|
92
|
+
transparent 100%
|
|
93
|
+
);
|
|
94
|
+
mask-image: linear-gradient(var(--ds-progressive-blur-toward), black 0%, black 55%, transparent 100%);
|
|
95
|
+
opacity: 0;
|
|
96
|
+
transition: opacity var(--motion-duration-slow) var(--motion-ease-standard);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* States */
|
|
100
|
+
.ds-progressive-blur--tinted::after {
|
|
101
|
+
opacity: 1;
|
|
102
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by ProgressiveBlur itself — everything else falls through to the root `<div>`. */
|
|
3
|
+
type ProgressiveBlurOwnProps = {
|
|
4
|
+
/**
|
|
5
|
+
* The side the blur is anchored to, as Drawer names its edge: fully
|
|
6
|
+
* frosted there, dissolving to clear toward the opposite side. `top` sits
|
|
7
|
+
* behind a header, `bottom` behind a toolbar or a footer bar.
|
|
8
|
+
*/
|
|
9
|
+
side?: 'top' | 'bottom';
|
|
10
|
+
/**
|
|
11
|
+
* Whether the page-surface tint shows over the blur. It fades on change,
|
|
12
|
+
* so a header can bring it in once the page has scrolled; the blur
|
|
13
|
+
* itself never fades.
|
|
14
|
+
*/
|
|
15
|
+
tinted?: boolean;
|
|
16
|
+
/** Additional CSS classes on the root. */
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
export interface ProgressiveBlurProps extends ProgressiveBlurOwnProps, Omit<React.ComponentPropsWithRef<'div'>, keyof ProgressiveBlurOwnProps> {
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A backdrop blur that dissolves along one edge instead of ending in a hard
|
|
23
|
+
* line: four masked blur layers of rising strength, with an optional tint of
|
|
24
|
+
* the page surface on its own layer above them. It fills its positioned
|
|
25
|
+
* parent and is decorative, so it is hidden from assistive tech and lets the
|
|
26
|
+
* pointer through. The forwarded ref and any unrecognised props target the
|
|
27
|
+
* root `<div>`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function ProgressiveBlur({ side, tinted, className, ref, ...rest }: ProgressiveBlurProps): React.JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import "./ProgressiveBlur.css";
|
|
4
|
+
function ProgressiveBlur({
|
|
5
|
+
side = "top",
|
|
6
|
+
tinted = false,
|
|
7
|
+
className = "",
|
|
8
|
+
ref,
|
|
9
|
+
...rest
|
|
10
|
+
}) {
|
|
11
|
+
const baseClass = "ds-progressive-blur";
|
|
12
|
+
const classes = [
|
|
13
|
+
baseClass,
|
|
14
|
+
`${baseClass}--${side}`,
|
|
15
|
+
tinted && `${baseClass}--tinted`,
|
|
16
|
+
className
|
|
17
|
+
].filter(Boolean).join(" ");
|
|
18
|
+
return /* @__PURE__ */ jsxs("div", { "aria-hidden": "true", ...rest, ref, className: classes, children: [
|
|
19
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__layer` }),
|
|
20
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__layer` }),
|
|
21
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__layer` }),
|
|
22
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__layer` })
|
|
23
|
+
] });
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
ProgressiveBlur
|
|
27
|
+
};
|
|
@@ -508,7 +508,7 @@
|
|
|
508
508
|
.ds-prompt-suggestions--kept .ds-prompt-suggestions__tile,
|
|
509
509
|
.ds-prompt-suggestions--kept .ds-prompt-suggestions__card {
|
|
510
510
|
border-style: dashed;
|
|
511
|
-
border-color: var(--color-
|
|
511
|
+
border-color: var(--color-bg-container-border);
|
|
512
512
|
/* A record carries no fill, like QuestionCard's rows once answered: the
|
|
513
513
|
outline alone says which way the conversation went. */
|
|
514
514
|
background-color: transparent;
|
|
@@ -113,7 +113,8 @@
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
/* An open row is drawn dashed
|
|
116
|
+
/* An open row is drawn dashed, in the suggestion chip's hairline colour:
|
|
117
|
+
an answer on offer, not yet given. A pick
|
|
117
118
|
turns it solid, in the strongest ink, with the control's indicator on at
|
|
118
119
|
its end, so a chosen row reads as decided at a glance and stays readable
|
|
119
120
|
after the moment has passed. The row is a control, so it sits on Input's
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
min-width: 0;
|
|
129
130
|
margin: 0;
|
|
130
131
|
padding: var(--padding-300) var(--padding-400);
|
|
131
|
-
border: var(--border-025) dashed var(--color-
|
|
132
|
+
border: var(--border-025) dashed var(--color-bg-container-border);
|
|
132
133
|
border-radius: var(--radius-300);
|
|
133
134
|
background-color: var(--color-input-bg-primary);
|
|
134
135
|
color: var(--color-text-primary);
|
|
@@ -92,14 +92,8 @@ const QuestionCard = React.forwardRef(
|
|
|
92
92
|
return;
|
|
93
93
|
}
|
|
94
94
|
const next = { values: [option.value], other: "", otherOpen: false };
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
submit({ ...drafts, [current.id]: next });
|
|
98
|
-
} else if (step < questions.length - 1) {
|
|
99
|
-
advance(next);
|
|
100
|
-
} else {
|
|
101
|
-
writeDraft(current, next);
|
|
102
|
-
}
|
|
95
|
+
writeDraft(current, next);
|
|
96
|
+
if (!isSet) submit({ ...drafts, [current.id]: next });
|
|
103
97
|
};
|
|
104
98
|
const openOther = () => {
|
|
105
99
|
if (!live) return;
|