rift-ds 1.5.0 → 1.7.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 -10
- package/bin/rift-ds.mjs +111 -37
- package/components/AgentRail/AgentRail.css +2 -2
- package/components/AppSidebar/AppSidebar.css +6 -0
- package/components/AppSidebar/AppSidebar.d.ts +12 -2
- package/components/AppSidebar/AppSidebar.js +11 -1
- package/components/Attachment/Attachment.css +14 -0
- package/components/Attachment/AttachmentGroup.d.ts +2 -2
- package/components/Attachment/AttachmentGroup.js +7 -2
- package/components/Composer/Composer.css +88 -4
- package/components/Composer/Composer.d.ts +21 -0
- package/components/Composer/Composer.js +199 -14
- package/components/Mention/Mention.css +195 -0
- package/components/Mention/Mention.d.ts +68 -0
- package/components/Mention/Mention.js +145 -0
- package/components/Mention/mentions.d.ts +81 -0
- package/components/Mention/mentions.js +83 -0
- 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/ShaderField/ShaderField.d.ts +3 -3
- package/components/SourceChip/SourceChip.css +211 -11
- package/components/SourceChip/SourceChip.d.ts +33 -10
- package/components/SourceChip/SourceChip.js +174 -22
- package/components/StatusDot/StatusDot.css +36 -13
- package/components/StatusDot/StatusDot.d.ts +16 -4
- package/components/StatusDot/StatusDot.js +25 -5
- package/components/ThreadPanel/ThreadPanel.css +26 -11
- package/components/ThreadPanel/ThreadPanel.d.ts +18 -4
- package/components/ThreadPanel/ThreadPanel.js +52 -10
- package/components/ThreadTabs/ThreadTabs.css +18 -8
- package/components/ThreadTabs/ThreadTabs.d.ts +8 -2
- package/components/ThreadTabs/ThreadTabs.js +24 -5
- 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 +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 +21 -0
- package/package.json +5 -1
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* ============================================
|
|
2
2
|
THREAD TABS COMPONENT
|
|
3
3
|
The strip of open chat sessions across a conversation's top edge: pill
|
|
4
|
-
tabs with a leading glyph,
|
|
4
|
+
tabs with a leading glyph, a status dot, a hover-revealed close button,
|
|
5
5
|
and a trailing new-tab action. Deliberately surface-less — the host
|
|
6
6
|
paints the band it sits on.
|
|
7
7
|
|
|
@@ -148,14 +148,24 @@
|
|
|
148
148
|
outline-offset: -2px;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
/* The
|
|
152
|
-
|
|
153
|
-
.ds-thread-
|
|
151
|
+
/* The status dot: a StatusDot at its 8px list-row size leading the label,
|
|
152
|
+
the same mark ThreadPanel's rows carry. */
|
|
153
|
+
.ds-thread-tabs__status {
|
|
154
154
|
flex: none;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* The status read aloud: the dot is decorative, so its state rides in the
|
|
158
|
+
tab's text for assistive technology only. */
|
|
159
|
+
.ds-thread-tabs__status-label {
|
|
160
|
+
position: absolute;
|
|
161
|
+
width: 1px;
|
|
162
|
+
height: 1px;
|
|
163
|
+
padding: 0;
|
|
164
|
+
margin: -1px;
|
|
165
|
+
overflow: hidden;
|
|
166
|
+
clip: rect(0, 0, 0, 0);
|
|
167
|
+
white-space: nowrap;
|
|
168
|
+
border: 0;
|
|
159
169
|
}
|
|
160
170
|
|
|
161
171
|
.ds-thread-tabs__icon {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
/** What a tab's leading dot reports — ThreadPanel's thread statuses, so a session reads the same in the rail and in the strip. */
|
|
3
|
+
export type ThreadTabStatus = 'idle' | 'working' | 'unread' | 'waiting' | 'error';
|
|
2
4
|
export interface ThreadTab {
|
|
3
5
|
/** Stable identifier: `activeId` matches against it and the callbacks report it. */
|
|
4
6
|
id: string;
|
|
@@ -6,7 +8,9 @@ export interface ThreadTab {
|
|
|
6
8
|
label: string;
|
|
7
9
|
/** The tab's leading icon — Material Symbol name (string) or custom element (ReactNode). */
|
|
8
10
|
icon?: string | React.ReactNode;
|
|
9
|
-
/** The thread
|
|
11
|
+
/** The thread's state, drawn as a dot leading the label: `working` pulses in neutral, `unread`, `waiting` and `error` are solid in the info, warning and error roles. An `idle` tab draws no dot: a strip has no left edge to keep, so only a state worth a glance takes the room. The dot is decorative; the state is also read aloud through `statusLabels`. */
|
|
12
|
+
status?: ThreadTabStatus;
|
|
13
|
+
/** Legacy boolean for `status: 'unread'`, ignored when `status` is set. @deprecated Use `status: 'unread'` instead. */
|
|
10
14
|
unread?: boolean;
|
|
11
15
|
}
|
|
12
16
|
/** Props owned by ThreadTabs itself — everything else falls through to the root `<div>`. */
|
|
@@ -19,6 +23,8 @@ type ThreadTabsOwnProps = {
|
|
|
19
23
|
onTabSelect?: (id: string) => void;
|
|
20
24
|
/** Fires with the tab's id when its close button is pressed, or Delete lands on the focused tab. The close affordance renders only when this is given. */
|
|
21
25
|
onTabClose?: (id: string) => void;
|
|
26
|
+
/** Spoken text for each tab status, read after the tab's label; the dot itself is decorative. Merged over the English defaults (Working, Unread, Needs input, Failed). */
|
|
27
|
+
statusLabels?: Partial<Record<ThreadTabStatus, string>>;
|
|
22
28
|
/** Accessible name for a tab's close button; the tab's label is appended after it. */
|
|
23
29
|
closeLabel?: string;
|
|
24
30
|
/** Fires when the trailing new-tab button is pressed. The button renders only when this is given. */
|
|
@@ -34,7 +40,7 @@ export interface ThreadTabsProps extends ThreadTabsOwnProps, Omit<React.Componen
|
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* ThreadTabs is the strip of open chat sessions across a conversation's top
|
|
37
|
-
* edge: pill tabs with a leading glyph,
|
|
43
|
+
* edge: pill tabs with a leading glyph, a status dot, a hover-revealed
|
|
38
44
|
* close button, and a trailing new-tab action. Fully controlled — the host
|
|
39
45
|
* owns which tabs exist and which is active; the strip owns the
|
|
40
46
|
* choreography of a tab arriving and leaving. A removed tab is kept on
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
|
+
import { StatusDot } from "../StatusDot/StatusDot.js";
|
|
4
5
|
import "./ThreadTabs.css";
|
|
5
6
|
import "../../fonts/material-symbols.css";
|
|
6
7
|
const baseClass = "ds-thread-tabs";
|
|
8
|
+
const STATUS_DOTS = {
|
|
9
|
+
working: { variant: "neutral", pulse: true },
|
|
10
|
+
unread: { variant: "info" },
|
|
11
|
+
waiting: { variant: "warning" },
|
|
12
|
+
error: { variant: "error" }
|
|
13
|
+
};
|
|
14
|
+
const DEFAULT_STATUS_LABELS = {
|
|
15
|
+
working: "Working",
|
|
16
|
+
unread: "Unread",
|
|
17
|
+
waiting: "Needs input",
|
|
18
|
+
error: "Failed"
|
|
19
|
+
};
|
|
7
20
|
const ThreadTabs = React.forwardRef(
|
|
8
21
|
({
|
|
9
22
|
tabs,
|
|
10
23
|
activeId,
|
|
11
24
|
onTabSelect,
|
|
12
25
|
onTabClose,
|
|
26
|
+
statusLabels,
|
|
13
27
|
closeLabel = "Close thread",
|
|
14
28
|
onAdd,
|
|
15
29
|
addLabel = "New thread",
|
|
@@ -18,6 +32,7 @@ const ThreadTabs = React.forwardRef(
|
|
|
18
32
|
...rest
|
|
19
33
|
}, ref) => {
|
|
20
34
|
const iconClass = "material-symbols-rounded";
|
|
35
|
+
const labels = { ...DEFAULT_STATUS_LABELS, ...statusLabels };
|
|
21
36
|
const listRef = React.useRef(null);
|
|
22
37
|
const enteredRef = React.useRef(
|
|
23
38
|
new Set(tabs.map((tab) => tab.id))
|
|
@@ -90,6 +105,7 @@ const ThreadTabs = React.forwardRef(
|
|
|
90
105
|
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
91
106
|
/* @__PURE__ */ jsx("ul", { className: `${baseClass}__list`, "aria-label": ariaLabel, ref: listRef, children: entries.map(({ tab, leaving: isLeaving }) => {
|
|
92
107
|
const active = !isLeaving && tab.id === activeId;
|
|
108
|
+
const status = tab.status ?? (tab.unread ? "unread" : "idle");
|
|
93
109
|
const entering = !isLeaving && !enteredRef.current.has(tab.id);
|
|
94
110
|
return /* @__PURE__ */ jsx(
|
|
95
111
|
"li",
|
|
@@ -138,11 +154,13 @@ const ThreadTabs = React.forwardRef(
|
|
|
138
154
|
}
|
|
139
155
|
},
|
|
140
156
|
children: [
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
status !== "idle" && /* @__PURE__ */ jsx(
|
|
158
|
+
StatusDot,
|
|
143
159
|
{
|
|
144
|
-
className: `${baseClass}
|
|
145
|
-
|
|
160
|
+
className: `${baseClass}__status`,
|
|
161
|
+
size: "xs",
|
|
162
|
+
decorative: true,
|
|
163
|
+
...STATUS_DOTS[status]
|
|
146
164
|
}
|
|
147
165
|
),
|
|
148
166
|
tab.icon && (typeof tab.icon === "string" ? /* @__PURE__ */ jsx(
|
|
@@ -160,7 +178,8 @@ const ThreadTabs = React.forwardRef(
|
|
|
160
178
|
children: tab.icon
|
|
161
179
|
}
|
|
162
180
|
)),
|
|
163
|
-
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: tab.label })
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: tab.label }),
|
|
182
|
+
labels[status] && /* @__PURE__ */ jsx("span", { className: `${baseClass}__status-label`, children: labels[status] })
|
|
164
183
|
]
|
|
165
184
|
}
|
|
166
185
|
),
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
WIDGET COMPONENT
|
|
3
|
+
A titled tile for a dashboard or home screen,
|
|
4
|
+
with its rows, its groups, and the board that
|
|
5
|
+
packs tiles into columns
|
|
6
|
+
============================================ */
|
|
7
|
+
|
|
8
|
+
/* Tile — the translucent container behind a hairline, blurred so the body
|
|
9
|
+
stays on a calm field when the tile sits over an ambient background. The
|
|
10
|
+
navigation-tile radius, per the radius scale. */
|
|
11
|
+
|
|
12
|
+
.ds-widget {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: var(--gap-300);
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
padding: var(--padding-500);
|
|
19
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
20
|
+
border-radius: var(--radius-600);
|
|
21
|
+
background-color: var(--color-bg-container-primary-semi);
|
|
22
|
+
-webkit-backdrop-filter: blur(24px);
|
|
23
|
+
backdrop-filter: blur(24px);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ds-widget__header {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
gap: var(--gap-200);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ds-widget__title {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: baseline;
|
|
36
|
+
gap: var(--gap-200);
|
|
37
|
+
min-width: 0;
|
|
38
|
+
margin: 0;
|
|
39
|
+
font-family: var(--font-title-body-family);
|
|
40
|
+
font-size: var(--font-title-body-size);
|
|
41
|
+
font-weight: var(--font-title-body-weight);
|
|
42
|
+
line-height: var(--font-title-body-line-height);
|
|
43
|
+
letter-spacing: var(--font-title-body-letter-spacing);
|
|
44
|
+
color: var(--color-text-primary);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ds-widget__count {
|
|
48
|
+
font-family: var(--font-paragraph-sm-family);
|
|
49
|
+
font-size: var(--font-paragraph-sm-size);
|
|
50
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
51
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
52
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
53
|
+
color: var(--color-text-tertiary);
|
|
54
|
+
font-variant-numeric: tabular-nums;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ds-widget__action {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
flex-shrink: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ds-widget__body {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: var(--gap-100);
|
|
66
|
+
min-width: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Group — a labelled run of rows */
|
|
70
|
+
|
|
71
|
+
.ds-widget-group {
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: var(--gap-100);
|
|
75
|
+
min-width: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.ds-widget-group + .ds-widget-group {
|
|
79
|
+
margin-top: var(--gap-300);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.ds-widget-group__label {
|
|
83
|
+
font-family: var(--font-caption-family);
|
|
84
|
+
font-size: var(--font-caption-size);
|
|
85
|
+
font-weight: var(--font-caption-weight);
|
|
86
|
+
line-height: var(--font-caption-line-height);
|
|
87
|
+
letter-spacing: var(--font-caption-letter-spacing);
|
|
88
|
+
color: var(--color-text-tertiary);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Row — a leading mark, a title over a description, a trailing fact */
|
|
92
|
+
|
|
93
|
+
.ds-widget-row {
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
gap: var(--gap-300);
|
|
97
|
+
box-sizing: border-box;
|
|
98
|
+
width: 100%;
|
|
99
|
+
min-width: 0;
|
|
100
|
+
margin: 0;
|
|
101
|
+
padding: var(--padding-150) 0;
|
|
102
|
+
border: 0;
|
|
103
|
+
background: none;
|
|
104
|
+
color: inherit;
|
|
105
|
+
font: inherit;
|
|
106
|
+
text-align: left;
|
|
107
|
+
text-decoration: none;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.ds-widget-row__leading {
|
|
111
|
+
display: inline-flex;
|
|
112
|
+
flex-shrink: 0;
|
|
113
|
+
align-items: center;
|
|
114
|
+
--icon-size: var(--icon-size-600);
|
|
115
|
+
color: var(--color-icon-secondary);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ds-widget-row__main {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex: 1;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
min-width: 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ds-widget-row__title,
|
|
126
|
+
.ds-widget-row__description {
|
|
127
|
+
overflow: hidden;
|
|
128
|
+
text-overflow: ellipsis;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.ds-widget-row__title {
|
|
133
|
+
font-family: var(--font-paragraph-sm-emphasis-family);
|
|
134
|
+
font-size: var(--font-paragraph-sm-emphasis-size);
|
|
135
|
+
font-weight: var(--font-paragraph-sm-emphasis-weight);
|
|
136
|
+
line-height: var(--font-paragraph-sm-emphasis-line-height);
|
|
137
|
+
letter-spacing: var(--font-paragraph-sm-emphasis-letter-spacing);
|
|
138
|
+
color: var(--color-text-primary);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ds-widget-row__description {
|
|
142
|
+
font-family: var(--font-caption-family);
|
|
143
|
+
font-size: var(--font-caption-size);
|
|
144
|
+
font-weight: var(--font-caption-weight);
|
|
145
|
+
line-height: var(--font-caption-line-height);
|
|
146
|
+
letter-spacing: var(--font-caption-letter-spacing);
|
|
147
|
+
color: var(--color-text-tertiary);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ds-widget-row__meta {
|
|
151
|
+
flex-shrink: 0;
|
|
152
|
+
font-family: var(--font-caption-family);
|
|
153
|
+
font-size: var(--font-caption-size);
|
|
154
|
+
font-weight: var(--font-caption-weight);
|
|
155
|
+
line-height: var(--font-caption-line-height);
|
|
156
|
+
letter-spacing: var(--font-caption-letter-spacing);
|
|
157
|
+
color: var(--color-text-secondary);
|
|
158
|
+
font-variant-numeric: tabular-nums;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* A row that goes somewhere: the hover fill bleeds past the text into the
|
|
162
|
+
tile's padding, so the whole line reads as one target. */
|
|
163
|
+
|
|
164
|
+
.ds-widget-row--interactive {
|
|
165
|
+
width: calc(100% + 2 * var(--padding-200));
|
|
166
|
+
margin-inline: calc(-1 * var(--padding-200));
|
|
167
|
+
padding-inline: var(--padding-200);
|
|
168
|
+
border-radius: var(--radius-300);
|
|
169
|
+
cursor: pointer;
|
|
170
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.ds-widget-row--interactive:hover {
|
|
174
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ds-widget-row--interactive:focus-visible {
|
|
178
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
179
|
+
outline-offset: 2px;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Grid — CSS columns, so tiles of different heights pack with no holes and
|
|
183
|
+
the board folds as it narrows. The column floor is stated on the icon
|
|
184
|
+
scale (seven cover icons, the narrowest a row of title, description and
|
|
185
|
+
fact stays readable), not as a breakpoint. */
|
|
186
|
+
|
|
187
|
+
.ds-widget-grid {
|
|
188
|
+
column-gap: var(--gap-400);
|
|
189
|
+
column-width: calc(var(--icon-size-1200) * 7);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.ds-widget-grid--columns-1 {
|
|
193
|
+
column-count: 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.ds-widget-grid--columns-2 {
|
|
197
|
+
column-count: 2;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ds-widget-grid--columns-3 {
|
|
201
|
+
column-count: 3;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.ds-widget-grid > * {
|
|
205
|
+
break-inside: avoid;
|
|
206
|
+
margin-bottom: var(--gap-400);
|
|
207
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Widget itself — everything else falls through to the root `<section>`. */
|
|
3
|
+
type WidgetOwnProps = {
|
|
4
|
+
/** The tile's heading. Also the section's accessible name, unless an `aria-label` is passed. Note: this shadows the native `title` tooltip attribute, which Widget does not expose. */
|
|
5
|
+
title: string;
|
|
6
|
+
/** A quiet figure after the title: how many rows the tile holds, how many are open. */
|
|
7
|
+
count?: number;
|
|
8
|
+
/** Trailing header slot, opposite the title — a compact button, a link, a period label. */
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
/** Heading element for the title, so the tile takes its place in the page's outline. */
|
|
11
|
+
titleAs?: 'h2' | 'h3' | 'h4';
|
|
12
|
+
/** The tile's body: WidgetRows, WidgetGroups, a chart, a figure, anything. */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Additional CSS classes */
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
export interface WidgetProps extends WidgetOwnProps, Omit<React.ComponentPropsWithoutRef<'section'>, keyof WidgetOwnProps> {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Widget — a titled tile for a dashboard or a home screen: a heading with an
|
|
21
|
+
* optional count, then whatever the tile is about. The surface is the
|
|
22
|
+
* system's translucent container behind a hairline, so a board of them sits
|
|
23
|
+
* over an ambient background without going flat. Compose the body from
|
|
24
|
+
* WidgetRow and WidgetGroup for lists, or pass a chart or a figure.
|
|
25
|
+
*
|
|
26
|
+
* Purely presentational: safe to render from a Server Component.
|
|
27
|
+
*/
|
|
28
|
+
export declare const Widget: React.ForwardRefExoticComponent<WidgetProps & React.RefAttributes<HTMLElement>>;
|
|
29
|
+
/** Props owned by WidgetGroup itself — everything else falls through to the root `<div>`. */
|
|
30
|
+
type WidgetGroupOwnProps = {
|
|
31
|
+
/** The run's quiet label, e.g. "Waiting on you". */
|
|
32
|
+
label: string;
|
|
33
|
+
/** The rows in this run. */
|
|
34
|
+
children?: React.ReactNode;
|
|
35
|
+
/** Additional CSS classes */
|
|
36
|
+
className?: string;
|
|
37
|
+
};
|
|
38
|
+
export interface WidgetGroupProps extends WidgetGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof WidgetGroupOwnProps> {
|
|
39
|
+
}
|
|
40
|
+
/** WidgetGroup — splits a Widget's rows into labelled runs. */
|
|
41
|
+
export declare const WidgetGroup: React.ForwardRefExoticComponent<WidgetGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
42
|
+
/** Props owned by WidgetRow itself — everything else falls through to the root element. */
|
|
43
|
+
type WidgetRowOwnProps = {
|
|
44
|
+
/** The row's main line. Note: this shadows the native `title` tooltip attribute, which WidgetRow does not expose. */
|
|
45
|
+
title: string;
|
|
46
|
+
/** A quiet second line under the title: who, where, or how much. */
|
|
47
|
+
description?: string;
|
|
48
|
+
/** Leading mark — a StatusDot, a PixelAvatar, an Avatar, a Spinner, an icon. Decorative unless the element names itself. */
|
|
49
|
+
leading?: React.ReactNode;
|
|
50
|
+
/** Trailing fact in the caption face: a date, an amount, a state. */
|
|
51
|
+
meta?: React.ReactNode;
|
|
52
|
+
/** Renders the row as a link to this URL. */
|
|
53
|
+
href?: string;
|
|
54
|
+
/** Additional CSS classes */
|
|
55
|
+
className?: string;
|
|
56
|
+
};
|
|
57
|
+
export interface WidgetRowProps extends WidgetRowOwnProps, Omit<React.HTMLAttributes<HTMLElement>, keyof WidgetRowOwnProps> {
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* WidgetRow — one line inside a Widget: a leading mark, a title over an
|
|
61
|
+
* optional description, and a trailing fact. It is a link when given an
|
|
62
|
+
* `href`, a button when given an `onClick`, and a plain row otherwise, so a
|
|
63
|
+
* list only offers a target where there is somewhere to go.
|
|
64
|
+
*/
|
|
65
|
+
export declare const WidgetRow: React.ForwardRefExoticComponent<WidgetRowProps & React.RefAttributes<HTMLElement>>;
|
|
66
|
+
/** Props owned by WidgetGrid itself — everything else falls through to the root `<div>`. */
|
|
67
|
+
type WidgetGridOwnProps = {
|
|
68
|
+
/** The most columns the board runs to. It folds to fewer as its own width narrows. */
|
|
69
|
+
columns?: 1 | 2 | 3;
|
|
70
|
+
/** The Widgets on the board, in reading order: they fill the first column, then the next. */
|
|
71
|
+
children?: React.ReactNode;
|
|
72
|
+
/** Additional CSS classes */
|
|
73
|
+
className?: string;
|
|
74
|
+
};
|
|
75
|
+
export interface WidgetGridProps extends WidgetGridOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof WidgetGridOwnProps> {
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* WidgetGrid — lays Widgets out as a board. Tiles of different heights pack
|
|
79
|
+
* into columns with no holes beside the tall ones, and the board folds to
|
|
80
|
+
* fewer columns as it narrows, with no breakpoint to configure.
|
|
81
|
+
*/
|
|
82
|
+
export declare const WidgetGrid: React.ForwardRefExoticComponent<WidgetGridProps & React.RefAttributes<HTMLDivElement>>;
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Widget.css";
|
|
4
|
+
const Widget = React.forwardRef(
|
|
5
|
+
({ title, count, action, titleAs: Title = "h3", children, className = "", ...rest }, ref) => {
|
|
6
|
+
const baseClass = "ds-widget";
|
|
7
|
+
return /* @__PURE__ */ jsxs(
|
|
8
|
+
"section",
|
|
9
|
+
{
|
|
10
|
+
"aria-label": title,
|
|
11
|
+
...rest,
|
|
12
|
+
ref,
|
|
13
|
+
className: [baseClass, className].filter(Boolean).join(" "),
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsxs("header", { className: `${baseClass}__header`, children: [
|
|
16
|
+
/* @__PURE__ */ jsxs(Title, { className: `${baseClass}__title`, children: [
|
|
17
|
+
title,
|
|
18
|
+
count !== void 0 && /* @__PURE__ */ jsx("span", { className: `${baseClass}__count`, children: count })
|
|
19
|
+
] }),
|
|
20
|
+
action && /* @__PURE__ */ jsx("span", { className: `${baseClass}__action`, children: action })
|
|
21
|
+
] }),
|
|
22
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__body`, children })
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
Widget.displayName = "Widget";
|
|
29
|
+
const WidgetGroup = React.forwardRef(
|
|
30
|
+
({ label, children, className = "", ...rest }, ref) => {
|
|
31
|
+
const baseClass = "ds-widget-group";
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
role: "group",
|
|
36
|
+
"aria-label": label,
|
|
37
|
+
...rest,
|
|
38
|
+
ref,
|
|
39
|
+
className: [baseClass, className].filter(Boolean).join(" "),
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, "aria-hidden": "true", children: label }),
|
|
42
|
+
children
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
WidgetGroup.displayName = "WidgetGroup";
|
|
49
|
+
const WidgetRow = React.forwardRef(
|
|
50
|
+
({ title, description, leading, meta, href, className = "", onClick, ...rest }, ref) => {
|
|
51
|
+
const baseClass = "ds-widget-row";
|
|
52
|
+
const interactive = Boolean(href || onClick);
|
|
53
|
+
const classes = [baseClass, interactive ? `${baseClass}--interactive` : "", className].filter(Boolean).join(" ");
|
|
54
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
|
+
leading && /* @__PURE__ */ jsx("span", { className: `${baseClass}__leading`, children: leading }),
|
|
56
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__main`, children: [
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: title }),
|
|
58
|
+
description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__description`, children: description })
|
|
59
|
+
] }),
|
|
60
|
+
meta !== void 0 && meta !== null && /* @__PURE__ */ jsx("span", { className: `${baseClass}__meta`, children: meta })
|
|
61
|
+
] });
|
|
62
|
+
if (href) {
|
|
63
|
+
return /* @__PURE__ */ jsx(
|
|
64
|
+
"a",
|
|
65
|
+
{
|
|
66
|
+
...rest,
|
|
67
|
+
ref,
|
|
68
|
+
href,
|
|
69
|
+
className: classes,
|
|
70
|
+
onClick,
|
|
71
|
+
children: content
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (onClick) {
|
|
76
|
+
return /* @__PURE__ */ jsx(
|
|
77
|
+
"button",
|
|
78
|
+
{
|
|
79
|
+
...rest,
|
|
80
|
+
ref,
|
|
81
|
+
type: "button",
|
|
82
|
+
className: classes,
|
|
83
|
+
onClick,
|
|
84
|
+
children: content
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes, children: content });
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
WidgetRow.displayName = "WidgetRow";
|
|
92
|
+
const WidgetGrid = React.forwardRef(
|
|
93
|
+
({ columns = 2, children, className = "", ...rest }, ref) => {
|
|
94
|
+
const baseClass = "ds-widget-grid";
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
...rest,
|
|
99
|
+
ref,
|
|
100
|
+
className: [baseClass, `${baseClass}--columns-${columns}`, className].filter(Boolean).join(" "),
|
|
101
|
+
children
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
WidgetGrid.displayName = "WidgetGrid";
|
|
107
|
+
export {
|
|
108
|
+
Widget,
|
|
109
|
+
WidgetGrid,
|
|
110
|
+
WidgetGroup,
|
|
111
|
+
WidgetRow
|
|
112
|
+
};
|
package/components/registry.json
CHANGED
|
@@ -755,6 +755,14 @@
|
|
|
755
755
|
"category": "maps",
|
|
756
756
|
"client": false
|
|
757
757
|
},
|
|
758
|
+
{
|
|
759
|
+
"name": "Mention",
|
|
760
|
+
"label": "Mention",
|
|
761
|
+
"slug": "mention",
|
|
762
|
+
"description": "An inline reference to an entity or a skill, with the menu that @ or / opens while typing and the tag it leaves in the message.",
|
|
763
|
+
"category": "ai",
|
|
764
|
+
"client": true
|
|
765
|
+
},
|
|
758
766
|
{
|
|
759
767
|
"name": "MessageActions",
|
|
760
768
|
"label": "Message actions",
|
|
@@ -853,6 +861,14 @@
|
|
|
853
861
|
"category": "forms",
|
|
854
862
|
"client": true
|
|
855
863
|
},
|
|
864
|
+
{
|
|
865
|
+
"name": "PixelAvatar",
|
|
866
|
+
"label": "Pixel avatar",
|
|
867
|
+
"slug": "pixel-avatar",
|
|
868
|
+
"description": "A generated character mark drawn from a name: the same name is always the same pixel creature in the same ink.",
|
|
869
|
+
"category": "data-display",
|
|
870
|
+
"client": false
|
|
871
|
+
},
|
|
856
872
|
{
|
|
857
873
|
"name": "Popover",
|
|
858
874
|
"label": "Popover",
|
|
@@ -1017,7 +1033,7 @@
|
|
|
1017
1033
|
"slug": "source-chip",
|
|
1018
1034
|
"description": "A numbered citation pill linking a claim to its source.",
|
|
1019
1035
|
"category": "ai",
|
|
1020
|
-
"client":
|
|
1036
|
+
"client": true
|
|
1021
1037
|
},
|
|
1022
1038
|
{
|
|
1023
1039
|
"name": "SourceTrail",
|
|
@@ -1153,7 +1169,7 @@
|
|
|
1153
1169
|
"name": "ThreadTabs",
|
|
1154
1170
|
"label": "Thread tabs",
|
|
1155
1171
|
"slug": "thread-tabs",
|
|
1156
|
-
"description": "The strip of open chat sessions: pill tabs with
|
|
1172
|
+
"description": "The strip of open chat sessions: pill tabs with status dots and hover-revealed close buttons, a new-tab action, and animated enter and exit.",
|
|
1157
1173
|
"category": "ai",
|
|
1158
1174
|
"client": true
|
|
1159
1175
|
},
|
|
@@ -1263,6 +1279,14 @@
|
|
|
1263
1279
|
"category": "ai",
|
|
1264
1280
|
"client": false
|
|
1265
1281
|
},
|
|
1282
|
+
{
|
|
1283
|
+
"name": "Widget",
|
|
1284
|
+
"label": "Widget",
|
|
1285
|
+
"slug": "widget",
|
|
1286
|
+
"description": "A titled tile for a dashboard or home screen, with rows, labelled groups, and a board that packs tiles into columns.",
|
|
1287
|
+
"category": "data-display",
|
|
1288
|
+
"client": false
|
|
1289
|
+
},
|
|
1266
1290
|
{
|
|
1267
1291
|
"name": "WorldMap",
|
|
1268
1292
|
"label": "World map",
|
|
@@ -755,6 +755,14 @@ declare const _default: {
|
|
|
755
755
|
"category": "maps",
|
|
756
756
|
"client": false
|
|
757
757
|
},
|
|
758
|
+
{
|
|
759
|
+
"name": "Mention",
|
|
760
|
+
"label": "Mention",
|
|
761
|
+
"slug": "mention",
|
|
762
|
+
"description": "An inline reference to an entity or a skill, with the menu that @ or / opens while typing and the tag it leaves in the message.",
|
|
763
|
+
"category": "ai",
|
|
764
|
+
"client": true
|
|
765
|
+
},
|
|
758
766
|
{
|
|
759
767
|
"name": "MessageActions",
|
|
760
768
|
"label": "Message actions",
|
|
@@ -853,6 +861,14 @@ declare const _default: {
|
|
|
853
861
|
"category": "forms",
|
|
854
862
|
"client": true
|
|
855
863
|
},
|
|
864
|
+
{
|
|
865
|
+
"name": "PixelAvatar",
|
|
866
|
+
"label": "Pixel avatar",
|
|
867
|
+
"slug": "pixel-avatar",
|
|
868
|
+
"description": "A generated character mark drawn from a name: the same name is always the same pixel creature in the same ink.",
|
|
869
|
+
"category": "data-display",
|
|
870
|
+
"client": false
|
|
871
|
+
},
|
|
856
872
|
{
|
|
857
873
|
"name": "Popover",
|
|
858
874
|
"label": "Popover",
|
|
@@ -1017,7 +1033,7 @@ declare const _default: {
|
|
|
1017
1033
|
"slug": "source-chip",
|
|
1018
1034
|
"description": "A numbered citation pill linking a claim to its source.",
|
|
1019
1035
|
"category": "ai",
|
|
1020
|
-
"client":
|
|
1036
|
+
"client": true
|
|
1021
1037
|
},
|
|
1022
1038
|
{
|
|
1023
1039
|
"name": "SourceTrail",
|
|
@@ -1153,7 +1169,7 @@ declare const _default: {
|
|
|
1153
1169
|
"name": "ThreadTabs",
|
|
1154
1170
|
"label": "Thread tabs",
|
|
1155
1171
|
"slug": "thread-tabs",
|
|
1156
|
-
"description": "The strip of open chat sessions: pill tabs with
|
|
1172
|
+
"description": "The strip of open chat sessions: pill tabs with status dots and hover-revealed close buttons, a new-tab action, and animated enter and exit.",
|
|
1157
1173
|
"category": "ai",
|
|
1158
1174
|
"client": true
|
|
1159
1175
|
},
|
|
@@ -1263,6 +1279,14 @@ declare const _default: {
|
|
|
1263
1279
|
"category": "ai",
|
|
1264
1280
|
"client": false
|
|
1265
1281
|
},
|
|
1282
|
+
{
|
|
1283
|
+
"name": "Widget",
|
|
1284
|
+
"label": "Widget",
|
|
1285
|
+
"slug": "widget",
|
|
1286
|
+
"description": "A titled tile for a dashboard or home screen, with rows, labelled groups, and a board that packs tiles into columns.",
|
|
1287
|
+
"category": "data-display",
|
|
1288
|
+
"client": false
|
|
1289
|
+
},
|
|
1266
1290
|
{
|
|
1267
1291
|
"name": "WorldMap",
|
|
1268
1292
|
"label": "World map",
|