rift-ds 1.11.0 → 1.13.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 +8 -2
- package/behaviors/LinkProvider.d.ts +36 -0
- package/behaviors/LinkProvider.js +15 -0
- package/behaviors/visually-hidden.css +24 -0
- package/bin/rift-ds.mjs +5 -2
- package/chat/ChatAgentPane.css +5 -1
- package/chat/ChatProvider.d.ts +5 -1
- package/chat/ChatProvider.js +11 -1
- package/chat/ChatWidget.css +0 -36
- package/chat/ResponseActions.js +2 -1
- package/components/Accordion/Accordion.css +10 -3
- package/components/AgentPlan/AgentPlan.css +0 -12
- package/components/AgentPlan/AgentPlan.js +2 -1
- package/components/AgentStatus/AgentStatus.css +1 -1
- package/components/AiButton/AiButton.d.ts +7 -0
- package/components/AiButton/AiButton.js +4 -1
- package/components/AnimatedNumber/AnimatedNumber.css +0 -12
- package/components/AnimatedNumber/AnimatedNumber.js +2 -1
- package/components/AppLayout/AppLayout.d.ts +7 -0
- package/components/AppLayout/AppLayout.js +3 -1
- package/components/AppSidebar/AppSidebar.css +2 -2
- package/components/AppSidebar/AppSidebar.d.ts +7 -0
- package/components/AppSidebar/AppSidebar.js +8 -3
- package/components/Attachment/Attachment.css +0 -17
- package/components/Attachment/AttachmentTile.js +3 -2
- package/components/BottomNav/BottomNav.css +0 -9
- package/components/BottomNav/BottomNav.d.ts +7 -0
- package/components/BottomNav/BottomNav.js +7 -3
- package/components/Breadcrumb/Breadcrumb.d.ts +8 -0
- package/components/Breadcrumb/Breadcrumb.js +3 -2
- package/components/Button/Button.d.ts +7 -0
- package/components/Button/Button.js +4 -1
- package/components/Card/Card.d.ts +7 -0
- package/components/Card/Card.js +4 -1
- package/components/CardStack/CardStack.css +0 -11
- package/components/CardStack/CardStack.js +2 -1
- package/components/ChatMessage/ChatMessage.css +0 -12
- package/components/ChatMessage/ChatMessage.js +2 -1
- package/components/Checkbox/Checkbox.css +34 -25
- package/components/Checkbox/Checkbox.d.ts +34 -0
- package/components/Checkbox/Checkbox.js +64 -36
- package/components/CircularButton/CircularButton.d.ts +8 -0
- package/components/CircularButton/CircularButton.js +3 -1
- package/components/CodeDiff/CodeDiff.css +0 -11
- package/components/CodeDiff/CodeDiff.js +3 -2
- package/components/ColourSwatch/ColourSwatch.css +1 -0
- package/components/Combobox/Combobox.css +1 -8
- package/components/Combobox/Combobox.js +2 -1
- package/components/CommandPalette/CommandPalette.css +2 -25
- package/components/CommandPalette/CommandPalette.js +8 -5
- package/components/Composer/Composer.css +0 -12
- package/components/Composer/Composer.js +3 -2
- package/components/ContactCard/ContactCard.css +1 -1
- package/components/ContactCard/ContactCard.d.ts +7 -0
- package/components/ContactCard/ContactCard.js +4 -1
- package/components/ContextMenu/ContextMenu.css +1 -9
- package/components/ContextMenu/ContextMenu.js +3 -2
- package/components/Dialog/Dialog.css +2 -26
- package/components/Dialog/Dialog.js +8 -12
- package/components/Drawer/Drawer.css +2 -26
- package/components/Drawer/Drawer.js +8 -12
- package/components/Dropdown/ChosenMark.css +19 -0
- package/components/Dropdown/Dropdown.css +0 -12
- package/components/Dropdown/Dropdown.d.ts +23 -0
- package/components/Dropdown/Dropdown.js +18 -17
- package/components/DropdownMenu/DropdownMenu.css +3 -9
- package/components/DropdownMenu/DropdownMenu.js +3 -2
- package/components/FilterBar/FilterBar.css +0 -8
- package/components/FilterBar/FilterBar.js +9 -6
- package/components/GanttChart/GanttChart.css +0 -13
- package/components/GanttChart/GanttChart.js +3 -2
- package/components/Inspector/InspectorToggleSwitch.js +5 -10
- package/components/InterruptCard/InterruptCard.css +0 -12
- package/components/InterruptCard/InterruptCard.js +2 -1
- package/components/LinkList/LinkList.d.ts +8 -0
- package/components/LinkList/LinkList.js +3 -2
- package/components/ModelPicker/ModelPicker.css +4 -45
- package/components/ModelPicker/ModelPicker.js +13 -50
- package/components/MotionSwatch/MotionSwatch.css +1 -1
- package/components/NavList/NavList.d.ts +7 -0
- package/components/NavList/NavList.js +2 -0
- package/components/NotificationCenter/NotificationCenter.css +1 -13
- package/components/NotificationCenter/NotificationCenter.js +2 -1
- package/components/PromptSuggestions/PromptSuggestions.css +0 -11
- package/components/PromptSuggestions/PromptSuggestions.js +3 -2
- package/components/QuestionCard/QuestionCard.css +13 -22
- package/components/QuestionCard/QuestionCard.js +8 -13
- package/components/RadioButton/RadioButton.css +27 -11
- package/components/RadioButton/RadioButton.d.ts +18 -0
- package/components/RadioButton/RadioButton.js +12 -2
- package/components/RichDropdown/RichDropdown.css +0 -9
- package/components/RichDropdown/RichDropdown.js +2 -8
- package/components/SegmentedControl/SegmentedControl.css +2 -14
- package/components/SegmentedControl/SegmentedControl.d.ts +7 -0
- package/components/SegmentedControl/SegmentedControl.js +4 -2
- package/components/SelectionCard/SelectionCard.css +29 -160
- package/components/SelectionCard/SelectionCard.js +5 -35
- package/components/SidebarPanel/SidebarPanel.css +1 -1
- package/components/SidebarPanel/SidebarPanel.d.ts +7 -0
- package/components/SidebarPanel/SidebarPanel.js +4 -1
- package/components/SourceChip/SourceChip.d.ts +7 -0
- package/components/SourceChip/SourceChip.js +5 -3
- package/components/SourceTrail/SourceTrail.css +0 -13
- package/components/SourceTrail/SourceTrail.d.ts +7 -0
- package/components/SourceTrail/SourceTrail.js +4 -1
- package/components/SpacingSwatch/SpacingSwatch.css +1 -1
- package/components/Stepper/Stepper.css +0 -13
- package/components/Stepper/Stepper.js +2 -1
- package/components/Table/Table.css +0 -22
- package/components/Table/Table.js +3 -2
- package/components/ThreadPanel/ThreadPanel.css +2 -16
- package/components/ThreadPanel/ThreadPanel.d.ts +8 -0
- package/components/ThreadPanel/ThreadPanel.js +12 -4
- package/components/ThreadTabs/ThreadTabs.css +1 -15
- package/components/ThreadTabs/ThreadTabs.js +2 -1
- package/components/TimePicker/TimePicker.css +0 -12
- package/components/TimePicker/TimePicker.js +2 -8
- package/components/ToggleGroup/ToggleGroup.css +9 -2
- package/components/ToggleSwitch/ToggleSwitch.css +33 -27
- package/components/ToggleSwitch/ToggleSwitch.d.ts +19 -0
- package/components/ToggleSwitch/ToggleSwitch.js +17 -10
- package/components/Tooltip/Tooltip.css +33 -36
- package/components/Tooltip/Tooltip.d.ts +10 -0
- package/components/Tooltip/Tooltip.js +72 -3
- package/components/TopAppBar/TopAppBar.d.ts +7 -0
- package/components/TopAppBar/TopAppBar.js +4 -1
- package/components/Waveform/Waveform.css +0 -12
- package/components/Waveform/Waveform.js +2 -1
- package/components/Widget/Widget.d.ts +8 -0
- package/components/Widget/Widget.js +3 -2
- package/index.js +10 -4
- package/package.json +5 -1
- package/tokens/presets/mono.css +168 -168
package/README.md
CHANGED
|
@@ -62,7 +62,13 @@ Swap the scripted transport for `createFetchTransport('/api/chat')` and the pane
|
|
|
62
62
|
|
|
63
63
|
## Set up your agent
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
The quickest start is one file: save [AGENTS.md](https://rift-ds.com/AGENTS.md) at your project root, or paste it into your agent. It holds the install, the setup, the rules, and where to look things up.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
curl -o AGENTS.md https://rift-ds.com/AGENTS.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For the full setup, one command teaches a coding agent the system: it installs the generated agent skills into your project and prints the MCP connect line. The skills cover the library's rules, moving existing screens onto the tokens and components, and auditing styles against them.
|
|
66
72
|
|
|
67
73
|
```bash
|
|
68
74
|
npx rift-ds init
|
|
@@ -74,7 +80,7 @@ The MCP endpoint serves the component catalogue, per-component prop APIs, the to
|
|
|
74
80
|
claude mcp add --transport http rift-ds https://rift-ds.com/api/mcp
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
Every component's prop contract is also plain markdown (append `.md` to its docs URL), and [llms.txt](https://rift-ds.com/llms.txt) indexes every machine surface. A theme made in the [playground](https://rift-ds.com/playground) exports as
|
|
83
|
+
Every component's prop contract is also plain markdown (append `.md` to its docs URL), and [llms.txt](https://rift-ds.com/llms.txt) indexes every machine surface. A theme made in the [playground](https://rift-ds.com/playground) exports as one AGENTS.md that carries the setup, your theme in words and its CSS, so the agent can read the look as well as the code. Then just ask: "Build a settings page with Rift components."
|
|
78
84
|
|
|
79
85
|
## Theming
|
|
80
86
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The props a link component receives: every anchor attribute, the ref, and
|
|
4
|
+
* an `href` that is always a string. Next.js's `Link` takes these as they
|
|
5
|
+
* are; a router whose link takes `to` instead needs a one-line adapter:
|
|
6
|
+
* `({ href, ...props }) => <RouterLink to={href} {...props} />`.
|
|
7
|
+
*/
|
|
8
|
+
export type LinkComponentProps = React.ComponentPropsWithRef<'a'> & {
|
|
9
|
+
href: string;
|
|
10
|
+
};
|
|
11
|
+
/** A component that renders a link in place of a plain `<a>`, such as a router's. */
|
|
12
|
+
export type LinkComponent = React.ElementType<LinkComponentProps>;
|
|
13
|
+
export interface LinkProviderProps {
|
|
14
|
+
/**
|
|
15
|
+
* The link component every rift-ds link under this provider renders, such
|
|
16
|
+
* as Next.js's `Link`. Named like the instance prop it stands in for.
|
|
17
|
+
*/
|
|
18
|
+
linkComponent: LinkComponent;
|
|
19
|
+
/** The part of the app whose links it applies to, usually the whole app. */
|
|
20
|
+
children?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sets the link component for every client-rendered rift-ds component below
|
|
24
|
+
* it that takes an `href`, so their links navigate through the app's router
|
|
25
|
+
* instead of reloading the page. A component's own `linkComponent` prop
|
|
26
|
+
* wins over it. The link components that can render on the server cannot
|
|
27
|
+
* read a provider and take the prop alone (design.md's Components intro
|
|
28
|
+
* names them, and scripts/validate-component-contract.mjs keeps them off
|
|
29
|
+
* the provider).
|
|
30
|
+
*/
|
|
31
|
+
export declare function LinkProvider({ linkComponent, children }: LinkProviderProps): React.JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* The link component to render: the component's own `linkComponent` prop,
|
|
34
|
+
* else the nearest LinkProvider's, else a plain `<a>`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useLinkComponent(override?: LinkComponent): LinkComponent;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
const LinkContext = createContext(null);
|
|
5
|
+
function LinkProvider({ linkComponent, children }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(LinkContext.Provider, { value: linkComponent, children });
|
|
7
|
+
}
|
|
8
|
+
function useLinkComponent(override) {
|
|
9
|
+
const provided = useContext(LinkContext);
|
|
10
|
+
return override ?? provided ?? "a";
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
LinkProvider,
|
|
14
|
+
useLinkComponent
|
|
15
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
VISUALLY HIDDEN
|
|
3
|
+
The one recipe for text that is read but not
|
|
4
|
+
seen: a status for a live region, a control's
|
|
5
|
+
spoken name, a marker beside a visual state.
|
|
6
|
+
Every component imports this sheet and uses
|
|
7
|
+
ds-visually-hidden rather than writing the
|
|
8
|
+
recipe again (scripts/validate-shared-primitives.mjs
|
|
9
|
+
fails a second copy). A hidden native input
|
|
10
|
+
that must stay focusable is not this: it
|
|
11
|
+
keeps its own rule, with the reason beside it.
|
|
12
|
+
============================================ */
|
|
13
|
+
|
|
14
|
+
.ds-visually-hidden {
|
|
15
|
+
position: absolute;
|
|
16
|
+
width: 1px;
|
|
17
|
+
height: 1px;
|
|
18
|
+
padding: 0;
|
|
19
|
+
margin: -1px;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
clip: rect(0, 0, 0, 0);
|
|
22
|
+
white-space: nowrap;
|
|
23
|
+
border: 0;
|
|
24
|
+
}
|
package/bin/rift-ds.mjs
CHANGED
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
* Zero dependencies by design: global fetch plus node:fs, so npx never
|
|
29
29
|
* installs anything beyond the package itself. SITE_ORIGIN, SKILL_NAME,
|
|
30
30
|
* MCP_SERVER_NAME and PACKAGE_NAME are stamped by build-package.mjs from
|
|
31
|
-
* scripts/brand.mjs (the one home for brand facts)
|
|
31
|
+
* scripts/brand.mjs (the one home for brand facts), and CHAT_SLUG from
|
|
32
|
+
* the chat registry, the widget page's slug; running this file
|
|
32
33
|
* straight from source fails fast rather than guessing a domain.
|
|
33
34
|
* SKILL_NAME is the library skill, kept only for --out without --skill,
|
|
34
35
|
* which has always meant that one.
|
|
@@ -41,6 +42,7 @@ const SITE_ORIGIN = 'https://rift-ds.com';
|
|
|
41
42
|
const SKILL_NAME = 'rift-design-system';
|
|
42
43
|
const MCP_SERVER_NAME = 'rift-ds';
|
|
43
44
|
const PACKAGE_NAME = 'rift-ds';
|
|
45
|
+
const CHAT_SLUG = 'ai-chat';
|
|
44
46
|
const MANIFEST_URL = `${SITE_ORIGIN}/skill/manifest.json`;
|
|
45
47
|
const DEFAULT_DIR = join('.claude', 'skills');
|
|
46
48
|
const TEMPLATES_DIR = join(dirname(fileURLToPath(import.meta.url)), 'templates', 'chat');
|
|
@@ -229,7 +231,8 @@ function initChat({ app, dryRun }) {
|
|
|
229
231
|
console.log(
|
|
230
232
|
` 4. Your layout's viewport should set interactiveWidget: "resizes-content", so the phone takeover ends above the keyboard.`
|
|
231
233
|
);
|
|
232
|
-
console.log(`\
|
|
234
|
+
console.log(`\nHow to add it, the protocol and the server options: ${SITE_ORIGIN}/docs/chat`);
|
|
235
|
+
console.log(`Every prop: ${SITE_ORIGIN}/components/${CHAT_SLUG}`);
|
|
233
236
|
}
|
|
234
237
|
|
|
235
238
|
const args = process.argv.slice(2);
|
package/chat/ChatAgentPane.css
CHANGED
|
@@ -31,12 +31,16 @@
|
|
|
31
31
|
margin: 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/* The chat's card surface: container fill behind a hairline, like every
|
|
35
|
+
card in the conversation. The radius stays a step under the rail's
|
|
36
|
+
--radius-600, concentric with the shell it nests in. */
|
|
34
37
|
.ds-chat-agent-pane__card {
|
|
35
38
|
display: flex;
|
|
36
39
|
flex-direction: column;
|
|
37
40
|
gap: var(--gap-200);
|
|
38
41
|
padding: var(--padding-300);
|
|
39
|
-
background-color: var(--color-bg-container-
|
|
42
|
+
background-color: var(--color-bg-container-primary);
|
|
43
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
40
44
|
border-radius: var(--radius-400);
|
|
41
45
|
}
|
|
42
46
|
|
package/chat/ChatProvider.d.ts
CHANGED
|
@@ -36,7 +36,11 @@ export interface ChatProviderProps {
|
|
|
36
36
|
renderers?: ChatCardRenderers;
|
|
37
37
|
/** Draws an artifact's preview by kind, for artifacts that are live React content rather than a document or a URL. */
|
|
38
38
|
artifactRenderers?: ChatArtifactRenderers;
|
|
39
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Renders a same-site link in an answer. The default renders through the
|
|
41
|
+
* nearest LinkProvider's link component, else a plain anchor; passing
|
|
42
|
+
* this wins over both.
|
|
43
|
+
*/
|
|
40
44
|
renderLink?: ChatLinkRenderer;
|
|
41
45
|
/** Which hrefs in an answer become links. Everything else renders as text. */
|
|
42
46
|
isInternalHref?: (href: string) => boolean;
|
package/chat/ChatProvider.js
CHANGED
|
@@ -7,7 +7,17 @@ import { createFollowupsFetcher, followupTarget, DEFAULT_FALLBACK_FOLLOWUPS, pic
|
|
|
7
7
|
import { useThreads } from "./threads.js";
|
|
8
8
|
import { createFetchTransport } from "./transport.js";
|
|
9
9
|
import { DEFAULT_PLACEHOLDER_COPY, useChat } from "./useChat.js";
|
|
10
|
-
|
|
10
|
+
import { useLinkComponent } from "../behaviors/LinkProvider.js";
|
|
11
|
+
function DefaultChatLink({ href, children, onNavigate }) {
|
|
12
|
+
const Link = useLinkComponent();
|
|
13
|
+
return (
|
|
14
|
+
// The hook returns a stable reference from context (or 'a'), never a
|
|
15
|
+
// component created here, which is what the rule guards against.
|
|
16
|
+
// eslint-disable-next-line react-hooks/static-components
|
|
17
|
+
/* @__PURE__ */ jsx(Link, { href, onClick: onNavigate, children })
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
const defaultRenderLink = (props) => /* @__PURE__ */ jsx(DefaultChatLink, { ...props });
|
|
11
21
|
function ChatProvider({
|
|
12
22
|
transport,
|
|
13
23
|
endpoint = "/api/chat",
|
package/chat/ChatWidget.css
CHANGED
|
@@ -61,29 +61,6 @@
|
|
|
61
61
|
min-height: calc(40px + var(--padding-150) * 2);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/* The close button hugs the panel's clipped right edge, so its centred
|
|
65
|
-
bottom tooltip would lose its right cap to overflow: hidden. End-align
|
|
66
|
-
the last header tooltip to the button and walk the arrow back to the
|
|
67
|
-
button's centre (20px in, minus half the 8px arrow). */
|
|
68
|
-
.ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom,
|
|
69
|
-
.ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom {
|
|
70
|
-
left: auto;
|
|
71
|
-
right: 0;
|
|
72
|
-
transform: translateY(-4px);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom.ds-tooltip__panel--visible,
|
|
76
|
-
.ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom.ds-tooltip__panel--visible {
|
|
77
|
-
transform: translateY(0);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom .ds-tooltip__arrow,
|
|
81
|
-
.ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom .ds-tooltip__arrow {
|
|
82
|
-
left: auto;
|
|
83
|
-
right: 16px;
|
|
84
|
-
margin-left: 0;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
64
|
/* The placement menu's wrapper is only there to catch Escape; it must not
|
|
88
65
|
become a box of its own in the header's action row. */
|
|
89
66
|
.ds-chat-widget__placement-menu {
|
|
@@ -560,19 +537,6 @@
|
|
|
560
537
|
}
|
|
561
538
|
}
|
|
562
539
|
|
|
563
|
-
/* Visually hidden, still announced. */
|
|
564
|
-
.ds-chat-widget__sr-only {
|
|
565
|
-
position: absolute;
|
|
566
|
-
width: 1px;
|
|
567
|
-
height: 1px;
|
|
568
|
-
margin: -1px;
|
|
569
|
-
padding: 0;
|
|
570
|
-
overflow: hidden;
|
|
571
|
-
clip: rect(0 0 0 0);
|
|
572
|
-
white-space: nowrap;
|
|
573
|
-
border: 0;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
540
|
/* ============================================
|
|
577
541
|
THE RAILS — the optional session-history rail (leading) and agent pane
|
|
578
542
|
(trailing). Wide widgets seat them inline; narrow ones summon the history
|
package/chat/ResponseActions.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { createContext, useContext, useState, useRef, useEffect } from "react";
|
|
4
4
|
import { MOTION_FEEDBACK_RESET_MS } from "../tokens/motion.js";
|
|
5
5
|
import { useChatWidget } from "./context.js";
|
|
6
|
+
import "../behaviors/visually-hidden.css";
|
|
6
7
|
const ResponseActionsLabelsContext = createContext({
|
|
7
8
|
copy: "Copy response",
|
|
8
9
|
copied: "Copied",
|
|
@@ -79,7 +80,7 @@ function ResponseActions({ turn }) {
|
|
|
79
80
|
}
|
|
80
81
|
)
|
|
81
82
|
] }),
|
|
82
|
-
/* @__PURE__ */ jsx("span", { className: "ds-
|
|
83
|
+
/* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", "aria-live": "polite", children: copied ? labels.copiedAnnouncement : "" })
|
|
83
84
|
] });
|
|
84
85
|
}
|
|
85
86
|
export {
|
|
@@ -3,12 +3,17 @@
|
|
|
3
3
|
Collapsible content sections
|
|
4
4
|
============================================ */
|
|
5
5
|
|
|
6
|
+
/* The standard card surface (container fill, hairline border,
|
|
7
|
+
--radius-300), the one SelectionCard's and QuestionCard's option rows
|
|
8
|
+
share, so a collapsible section reads as a card on the page rather than
|
|
9
|
+
a hairline floating over it. */
|
|
6
10
|
.ds-accordion {
|
|
7
11
|
display: flex;
|
|
8
12
|
flex-direction: column;
|
|
9
13
|
width: 100%;
|
|
10
14
|
border: var(--border-025) solid var(--color-bg-container-border);
|
|
11
|
-
border-radius: var(--radius-
|
|
15
|
+
border-radius: var(--radius-300);
|
|
16
|
+
background-color: var(--color-bg-container-primary);
|
|
12
17
|
overflow: hidden;
|
|
13
18
|
}
|
|
14
19
|
|
|
@@ -42,14 +47,16 @@
|
|
|
42
47
|
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
/* Hover steps the header to the secondary fill, the collapsible-section
|
|
51
|
+
convention the agent cards (AgentPlan, SourceTrail, ToolCall) set. */
|
|
45
52
|
.ds-accordion__trigger:hover {
|
|
46
|
-
background-color: var(--color-
|
|
53
|
+
background-color: var(--color-bg-container-secondary);
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
.ds-accordion__trigger:focus-visible {
|
|
50
57
|
outline: 2px solid var(--color-action-primary-bg);
|
|
51
58
|
outline-offset: -2px;
|
|
52
|
-
border-radius: var(--radius-
|
|
59
|
+
border-radius: var(--radius-300);
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
/* ============================================
|
|
@@ -229,18 +229,6 @@
|
|
|
229
229
|
this span announces it.
|
|
230
230
|
============================================ */
|
|
231
231
|
|
|
232
|
-
.ds-agent-plan__sr {
|
|
233
|
-
position: absolute;
|
|
234
|
-
width: 1px;
|
|
235
|
-
height: 1px;
|
|
236
|
-
padding: 0;
|
|
237
|
-
margin: -1px;
|
|
238
|
-
overflow: hidden;
|
|
239
|
-
clip: rect(0, 0, 0, 0);
|
|
240
|
-
white-space: nowrap;
|
|
241
|
-
border: 0;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
232
|
/* Icons take the colour of the text around them. Explicit, not just
|
|
245
233
|
inherited by default: a consumer stylesheet that sets a colour on
|
|
246
234
|
.material-symbols-rounded itself (a common global default) would
|
|
@@ -3,6 +3,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import React, { useId, useState, useCallback } from "react";
|
|
4
4
|
import { Spinner } from "../Spinner/Spinner.js";
|
|
5
5
|
import "./AgentPlan.css";
|
|
6
|
+
import "../../behaviors/visually-hidden.css";
|
|
6
7
|
import "../../fonts/material-symbols.css";
|
|
7
8
|
const STEP_ICONS = {
|
|
8
9
|
pending: "circle",
|
|
@@ -88,7 +89,7 @@ const AgentPlan = React.forwardRef(
|
|
|
88
89
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: step.label }),
|
|
89
90
|
step.detail && /* @__PURE__ */ jsx("span", { className: `${baseClass}__detail`, children: step.detail })
|
|
90
91
|
] }),
|
|
91
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
92
|
+
/* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: statusText[status] })
|
|
92
93
|
]
|
|
93
94
|
},
|
|
94
95
|
index
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
display: flex;
|
|
220
220
|
width: 100%;
|
|
221
221
|
padding: var(--padding-150) var(--padding-300);
|
|
222
|
-
background-color: var(--color-bg-container-
|
|
222
|
+
background-color: var(--color-bg-container-primary);
|
|
223
223
|
border: var(--border-025) solid var(--color-bg-container-border);
|
|
224
224
|
border-radius: var(--radius-300);
|
|
225
225
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { LinkComponent } from '../../behaviors/LinkProvider';
|
|
2
3
|
import { PromptSuggestion } from '../PromptSuggestions/PromptSuggestions';
|
|
3
4
|
/** The content of AiButton's summary panel. */
|
|
4
5
|
export interface AiButtonSummary {
|
|
@@ -59,6 +60,12 @@ type AiButtonOwnProps = {
|
|
|
59
60
|
suggestionsLabel?: string;
|
|
60
61
|
/** Additional CSS classes */
|
|
61
62
|
className?: string;
|
|
63
|
+
/**
|
|
64
|
+
* The component the link renders with, such as Next.js's `Link`, so it
|
|
65
|
+
* navigates through the app's router. Wins over a LinkProvider's; a plain
|
|
66
|
+
* `<a>` when neither is set.
|
|
67
|
+
*/
|
|
68
|
+
linkComponent?: LinkComponent;
|
|
62
69
|
};
|
|
63
70
|
export interface AiButtonProps extends AiButtonOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof AiButtonOwnProps | 'type'> {
|
|
64
71
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useRef, useEffect } from "react";
|
|
4
|
+
import { useLinkComponent } from "../../behaviors/LinkProvider.js";
|
|
4
5
|
import { PromptSuggestions } from "../PromptSuggestions/PromptSuggestions.js";
|
|
5
6
|
import { Skeleton } from "../Skeleton/Skeleton.js";
|
|
6
7
|
import { StreamingText } from "../StreamingText/StreamingText.js";
|
|
@@ -25,9 +26,11 @@ const AiButton = React.forwardRef(
|
|
|
25
26
|
dismissLabel = "Dismiss summary",
|
|
26
27
|
suggestionsLabel = "Suggested prompts",
|
|
27
28
|
className = "",
|
|
29
|
+
linkComponent,
|
|
28
30
|
...rest
|
|
29
31
|
}, ref) => {
|
|
30
32
|
const baseClass = "ds-ai-button";
|
|
33
|
+
const Link = useLinkComponent(linkComponent);
|
|
31
34
|
const [hoverOpen, setHoverOpen] = useState(false);
|
|
32
35
|
const [dismissed, setDismissed] = useState(false);
|
|
33
36
|
const [phase, setPhase] = useState("skeleton");
|
|
@@ -91,7 +94,7 @@ const AiButton = React.forwardRef(
|
|
|
91
94
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__text`, children: label })
|
|
92
95
|
] });
|
|
93
96
|
const control = href && !disabled ? /* @__PURE__ */ jsx(
|
|
94
|
-
|
|
97
|
+
Link,
|
|
95
98
|
{
|
|
96
99
|
...rest,
|
|
97
100
|
ref,
|
|
@@ -17,15 +17,3 @@
|
|
|
17
17
|
font-variant-numeric: tabular-nums;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/* Visually hidden settled value — what a screen reader gets instead of the
|
|
21
|
-
rolling digits. */
|
|
22
|
-
.ds-animated-number__sr {
|
|
23
|
-
position: absolute;
|
|
24
|
-
width: 1px;
|
|
25
|
-
height: 1px;
|
|
26
|
-
margin: -1px;
|
|
27
|
-
padding: 0;
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
clip-path: inset(50%);
|
|
30
|
-
white-space: nowrap;
|
|
31
|
-
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useRef, useEffect } from "react";
|
|
4
4
|
import "./AnimatedNumber.css";
|
|
5
|
+
import "../../behaviors/visually-hidden.css";
|
|
5
6
|
import { MOTION_COUNT_UP_MS } from "../../tokens/motion.js";
|
|
6
7
|
const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
7
8
|
const prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia(REDUCED_MOTION_QUERY).matches;
|
|
@@ -45,7 +46,7 @@ const AnimatedNumber = React.forwardRef(
|
|
|
45
46
|
const classes = [baseClass, className].filter(Boolean).join(" ");
|
|
46
47
|
return /* @__PURE__ */ jsxs("span", { ...rest, ref, className: classes, children: [
|
|
47
48
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, "aria-hidden": "true", children: fmt(display) }),
|
|
48
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
49
|
+
/* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: fmt(value) })
|
|
49
50
|
] });
|
|
50
51
|
}
|
|
51
52
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { AppSidebarSection, AppSidebarProfile } from '../AppSidebar/AppSidebar';
|
|
3
|
+
import { LinkComponent } from '../../behaviors/LinkProvider';
|
|
3
4
|
/** Props owned by AppLayout itself — everything else falls through to the outer wrapper `<div>`. */
|
|
4
5
|
type AppLayoutOwnProps = {
|
|
5
6
|
/** Sidebar navigation sections */
|
|
@@ -28,6 +29,12 @@ type AppLayoutOwnProps = {
|
|
|
28
29
|
* follows the surrounding data-theme like any other component.
|
|
29
30
|
*/
|
|
30
31
|
theme?: 'dark' | 'inherit';
|
|
32
|
+
/**
|
|
33
|
+
* The component its links render with, such as Next.js's `Link`, so they
|
|
34
|
+
* navigate through the app's router; passed on to the AppSidebar rail. Wins over a
|
|
35
|
+
* LinkProvider's; a plain `<a>` when neither is set.
|
|
36
|
+
*/
|
|
37
|
+
linkComponent?: LinkComponent;
|
|
31
38
|
/** Additional CSS classes on outer wrapper */
|
|
32
39
|
className?: string;
|
|
33
40
|
};
|
|
@@ -16,6 +16,7 @@ const AppLayout = React.forwardRef(
|
|
|
16
16
|
logo,
|
|
17
17
|
children,
|
|
18
18
|
theme = "dark",
|
|
19
|
+
linkComponent,
|
|
19
20
|
className = "",
|
|
20
21
|
...rest
|
|
21
22
|
}, ref) => {
|
|
@@ -49,7 +50,8 @@ const AppLayout = React.forwardRef(
|
|
|
49
50
|
expanded,
|
|
50
51
|
onExpandedChange: handleExpandedChange,
|
|
51
52
|
logoText,
|
|
52
|
-
logo
|
|
53
|
+
logo,
|
|
54
|
+
linkComponent
|
|
53
55
|
}
|
|
54
56
|
),
|
|
55
57
|
/* @__PURE__ */ jsx("main", { className: `${baseClass}__main`, children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children }) })
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
.ds-app-sidebar__btn--active {
|
|
214
|
-
background-color: var(--color-action-passive-bg-
|
|
214
|
+
background-color: var(--color-action-passive-bg-active);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
.ds-app-sidebar__btn-left {
|
|
@@ -357,7 +357,7 @@
|
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
.ds-app-sidebar__sub-btn--active {
|
|
360
|
-
background-color: var(--color-action-passive-bg-
|
|
360
|
+
background-color: var(--color-action-passive-bg-active);
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
.ds-app-sidebar__sub-label {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { LinkComponent } from '../../behaviors/LinkProvider';
|
|
2
3
|
export interface AppSidebarSubItem {
|
|
3
4
|
/** Unique key for this sub-item */
|
|
4
5
|
key: string;
|
|
@@ -108,6 +109,12 @@ type AppSidebarOwnProps = {
|
|
|
108
109
|
footerSlot?: React.ReactNode;
|
|
109
110
|
/** Additional CSS classes */
|
|
110
111
|
className?: string;
|
|
112
|
+
/**
|
|
113
|
+
* The component its links render with, such as Next.js's `Link`, so they
|
|
114
|
+
* navigate through the app's router. Wins over a LinkProvider's; a plain
|
|
115
|
+
* `<a>` when neither is set.
|
|
116
|
+
*/
|
|
117
|
+
linkComponent?: LinkComponent;
|
|
111
118
|
/** Logo element — defaults to the built-in brand mark */
|
|
112
119
|
logo?: React.ReactNode;
|
|
113
120
|
/** Text shown next to logo when expanded */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useRef, useEffect, useCallback, useId } from "react";
|
|
4
|
+
import { useLinkComponent } from "../../behaviors/LinkProvider.js";
|
|
4
5
|
import { useLayer } from "../../behaviors/useLayer.js";
|
|
5
6
|
import { useFocusScope } from "../../behaviors/useFocusScope.js";
|
|
6
7
|
import { useScrollLock } from "../../behaviors/useScrollLock.js";
|
|
@@ -56,9 +57,11 @@ const AppSidebar = React.forwardRef(function AppSidebar2({
|
|
|
56
57
|
collapseLabel = "Collapse sidebar",
|
|
57
58
|
profileMoreLabel = "Profile options",
|
|
58
59
|
menuLabel = "Menu",
|
|
60
|
+
linkComponent,
|
|
59
61
|
...rest
|
|
60
62
|
}, ref) {
|
|
61
63
|
const baseClass = "ds-app-sidebar";
|
|
64
|
+
const Link = useLinkComponent(linkComponent);
|
|
62
65
|
const avatarSeed = (item) => typeof item.pixelAvatar === "string" ? item.pixelAvatar : item.label;
|
|
63
66
|
const avatarItems = sections.flatMap(
|
|
64
67
|
(section) => section.items.filter((item) => item.pixelAvatar)
|
|
@@ -279,6 +282,7 @@ const AppSidebar = React.forwardRef(function AppSidebar2({
|
|
|
279
282
|
mobileOpen && drilled && panelSource ? /* @__PURE__ */ jsx(
|
|
280
283
|
SidebarPanel,
|
|
281
284
|
{
|
|
285
|
+
linkComponent: Link,
|
|
282
286
|
className: `${baseClass}__drill`,
|
|
283
287
|
items: panelSource.items,
|
|
284
288
|
title: panelSource.label,
|
|
@@ -327,8 +331,8 @@ const AppSidebar = React.forwardRef(function AppSidebar2({
|
|
|
327
331
|
)
|
|
328
332
|
] });
|
|
329
333
|
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
330
|
-
isLink ? /* @__PURE__ */ jsx(
|
|
331
|
-
|
|
334
|
+
isLink && item.href ? /* @__PURE__ */ jsx(
|
|
335
|
+
Link,
|
|
332
336
|
{
|
|
333
337
|
className: itemClasses,
|
|
334
338
|
href: item.href,
|
|
@@ -408,7 +412,7 @@ const AppSidebar = React.forwardRef(function AppSidebar2({
|
|
|
408
412
|
children: subLabel
|
|
409
413
|
}
|
|
410
414
|
) : sub.href ? /* @__PURE__ */ jsx(
|
|
411
|
-
|
|
415
|
+
Link,
|
|
412
416
|
{
|
|
413
417
|
className: subClasses,
|
|
414
418
|
href: sub.href,
|
|
@@ -467,6 +471,7 @@ const AppSidebar = React.forwardRef(function AppSidebar2({
|
|
|
467
471
|
panelSource && !mobileOpen && /* @__PURE__ */ jsx(
|
|
468
472
|
SidebarPanel,
|
|
469
473
|
{
|
|
474
|
+
linkComponent: Link,
|
|
470
475
|
id: panelId,
|
|
471
476
|
className: [
|
|
472
477
|
`${baseClass}__panel`,
|
|
@@ -481,23 +481,6 @@ button.ds-attachment-tile__body:focus-visible,
|
|
|
481
481
|
outline-offset: 2px;
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
/* ============================================
|
|
485
|
-
VISUALLY HIDDEN
|
|
486
|
-
============================================ */
|
|
487
|
-
|
|
488
|
-
.ds-attachment-tile__sr-only,
|
|
489
|
-
.ds-attachment-group__sr-only {
|
|
490
|
-
position: absolute;
|
|
491
|
-
width: 1px;
|
|
492
|
-
height: 1px;
|
|
493
|
-
padding: 0;
|
|
494
|
-
margin: -1px;
|
|
495
|
-
overflow: hidden;
|
|
496
|
-
clip: rect(0, 0, 0, 0);
|
|
497
|
-
white-space: nowrap;
|
|
498
|
-
border: 0;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
484
|
/* ============================================
|
|
502
485
|
REDUCED MOTION
|
|
503
486
|
The global guard collapses the spin to a still arc, which still reads as
|
|
@@ -5,6 +5,7 @@ import { formatBytes, getFileExtension, getFileKind, getFileTypeLabel, matchesAc
|
|
|
5
5
|
import { renderTypeMark } from "./typeMark.js";
|
|
6
6
|
import "../../fonts/material-symbols.css";
|
|
7
7
|
import "./Attachment.css";
|
|
8
|
+
import "../../behaviors/visually-hidden.css";
|
|
8
9
|
const AttachmentTile = React.forwardRef(
|
|
9
10
|
({
|
|
10
11
|
name,
|
|
@@ -97,7 +98,7 @@ const AttachmentTile = React.forwardRef(
|
|
|
97
98
|
const stack = /* @__PURE__ */ jsxs("span", { className: `${baseClass}__stack`, children: [
|
|
98
99
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__mark`, children: mark }),
|
|
99
100
|
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__name`, title: name, children: [
|
|
100
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: name }),
|
|
101
102
|
head !== "" && /* @__PURE__ */ jsx("span", { className: `${baseClass}__name-head`, "aria-hidden": "true", children: head }),
|
|
102
103
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__name-tail`, "aria-hidden": "true", children: tail })
|
|
103
104
|
] }),
|
|
@@ -111,7 +112,7 @@ const AttachmentTile = React.forwardRef(
|
|
|
111
112
|
] });
|
|
112
113
|
} else if (showExcerpt) {
|
|
113
114
|
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: name }),
|
|
115
116
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__excerpt`, children: excerpt }),
|
|
116
117
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__corner`, children: cornerMark })
|
|
117
118
|
] });
|
|
@@ -141,15 +141,6 @@
|
|
|
141
141
|
padding: 0;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
.ds-bottom-nav__sr {
|
|
145
|
-
position: absolute;
|
|
146
|
-
width: 1px;
|
|
147
|
-
height: 1px;
|
|
148
|
-
overflow: hidden;
|
|
149
|
-
clip-path: inset(50%);
|
|
150
|
-
white-space: nowrap;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
144
|
.ds-bottom-nav__search {
|
|
154
145
|
display: none;
|
|
155
146
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { LinkComponent } from '../../behaviors/LinkProvider';
|
|
2
3
|
export interface BottomNavItem {
|
|
3
4
|
/** Unique key for this destination */
|
|
4
5
|
key: string;
|
|
@@ -67,6 +68,12 @@ type BottomNavOwnProps = {
|
|
|
67
68
|
badgeLabel?: (badge: number | string | true) => string;
|
|
68
69
|
/** Additional CSS classes */
|
|
69
70
|
className?: string;
|
|
71
|
+
/**
|
|
72
|
+
* The component its links render with, such as Next.js's `Link`, so they
|
|
73
|
+
* navigate through the app's router. Wins over a LinkProvider's; a plain
|
|
74
|
+
* `<a>` when neither is set.
|
|
75
|
+
*/
|
|
76
|
+
linkComponent?: LinkComponent;
|
|
70
77
|
};
|
|
71
78
|
export interface BottomNavProps extends BottomNavOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof BottomNavOwnProps> {
|
|
72
79
|
}
|