@actioneer/ads 1.0.8 → 1.0.9
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/DESIGN.md +42 -8
- package/README.md +16 -4
- package/components/assistant-ui/composer-harness.js +5 -4
- package/components/breadcrumbs.js +12 -12
- package/components/button.d.ts +16 -1
- package/components/button.js +7 -4
- package/components/chart.d.ts +31 -4
- package/components/chart.js +747 -572
- package/components/chip.d.ts +2 -1
- package/components/chip.js +37 -34
- package/components/filters.d.ts +37 -0
- package/components/filters.js +129 -0
- package/components/index.d.ts +1 -0
- package/components/index.js +447 -444
- package/components/modal.d.ts +2 -1
- package/components/modal.js +101 -90
- package/components/popover.d.ts +6 -1
- package/components/popover.js +74 -64
- package/components/sidebar.d.ts +15 -0
- package/components/sidebar.js +186 -149
- package/components/table.d.ts +8 -0
- package/components/table.js +357 -350
- package/components/tabs.d.ts +6 -1
- package/components/tabs.js +28 -31
- package/demo/components/add-to-artifact.js +3 -2
- package/examples/README.md +3 -2
- package/examples/campaign-analysis-screen.tsx +138 -0
- package/examples/campaigns-screen.tsx +439 -0
- package/lib/icons.js +3 -3
- package/llms.txt +81 -17
- package/manifest.json +1601 -83
- package/package.json +1 -1
package/components/tabs.d.ts
CHANGED
|
@@ -19,7 +19,12 @@ export declare const TabList: React.ForwardRefExoticComponent<TabListProps & Rea
|
|
|
19
19
|
export interface TabProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
20
20
|
value: string;
|
|
21
21
|
isDisabled?: boolean;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Optional trailing count (e.g. a filter's match count), rendered as the bare
|
|
24
|
+
* number 6px after the label. It stays quieter than the label: Regular
|
|
25
|
+
* weight and tabular figures in every state, tertiary grey when inactive and
|
|
26
|
+
* the primary-action teal when active.
|
|
27
|
+
*/
|
|
23
28
|
count?: number;
|
|
24
29
|
}
|
|
25
30
|
export declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement>>;
|
package/components/tabs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as
|
|
2
|
+
import { jsx as p, jsxs as E } from "react/jsx-runtime";
|
|
3
3
|
import * as r from "react";
|
|
4
4
|
import { MotionConfig as j, motion as $ } from "motion/react";
|
|
5
5
|
import { cva as L } from "class-variance-authority";
|
|
@@ -18,26 +18,26 @@ const U = r.forwardRef(
|
|
|
18
18
|
value: e,
|
|
19
19
|
defaultValue: t,
|
|
20
20
|
onValueChange: a,
|
|
21
|
-
variant:
|
|
21
|
+
variant: g,
|
|
22
22
|
orientation: c = "horizontal",
|
|
23
|
-
size:
|
|
23
|
+
size: m,
|
|
24
24
|
children: R,
|
|
25
25
|
...A
|
|
26
26
|
}, k) => {
|
|
27
|
-
const x = e !== void 0, [y, v] = r.useState(t), T = r.useId().replaceAll(":", ""), d = r.useId(),
|
|
27
|
+
const x = e !== void 0, [y, v] = r.useState(t), T = r.useId().replaceAll(":", ""), d = r.useId(), w = r.useRef([]), h = r.useRef(/* @__PURE__ */ new Set()), f = x ? e : y, I = r.useCallback(
|
|
28
28
|
(l) => {
|
|
29
29
|
x || v(l), a == null || a(l);
|
|
30
30
|
},
|
|
31
31
|
[x, a]
|
|
32
32
|
), i = r.useCallback((l) => {
|
|
33
|
-
|
|
33
|
+
w.current.includes(l) || w.current.push(l);
|
|
34
34
|
}, []), s = r.useMemo(
|
|
35
35
|
() => ({
|
|
36
36
|
value: f,
|
|
37
37
|
setValue: I,
|
|
38
38
|
baseId: T,
|
|
39
39
|
registerTab: i,
|
|
40
|
-
tabs:
|
|
40
|
+
tabs: w,
|
|
41
41
|
disabled: h,
|
|
42
42
|
thumbId: d,
|
|
43
43
|
orientation: c
|
|
@@ -51,7 +51,7 @@ const U = r.forwardRef(
|
|
|
51
51
|
c
|
|
52
52
|
]
|
|
53
53
|
);
|
|
54
|
-
return /* @__PURE__ */
|
|
54
|
+
return /* @__PURE__ */ p(P.Provider, { value: s, children: /* @__PURE__ */ p(
|
|
55
55
|
"div",
|
|
56
56
|
{
|
|
57
57
|
ref: k,
|
|
@@ -63,13 +63,13 @@ const U = r.forwardRef(
|
|
|
63
63
|
o
|
|
64
64
|
),
|
|
65
65
|
...A,
|
|
66
|
-
children: /* @__PURE__ */
|
|
66
|
+
children: /* @__PURE__ */ p(j, { reducedMotion: "user", children: R })
|
|
67
67
|
}
|
|
68
68
|
) });
|
|
69
69
|
}
|
|
70
70
|
);
|
|
71
71
|
U.displayName = "Tabs";
|
|
72
|
-
const C = L("inline-flex text-
|
|
72
|
+
const C = L("inline-flex text-m", {
|
|
73
73
|
variants: {
|
|
74
74
|
orientation: {
|
|
75
75
|
horizontal: b(
|
|
@@ -88,7 +88,7 @@ const C = L("inline-flex text-l", {
|
|
|
88
88
|
}), B = r.forwardRef(
|
|
89
89
|
({ className: o, ...e }, t) => {
|
|
90
90
|
const { orientation: a } = z("TabList");
|
|
91
|
-
return /* @__PURE__ */
|
|
91
|
+
return /* @__PURE__ */ p(
|
|
92
92
|
"div",
|
|
93
93
|
{
|
|
94
94
|
ref: t,
|
|
@@ -127,7 +127,7 @@ const H = L(
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
), O = r.forwardRef(
|
|
130
|
-
({ className: o, value: e, isDisabled: t, count: a, children:
|
|
130
|
+
({ className: o, value: e, isDisabled: t, count: a, children: g, onClick: c, onKeyDown: m, ...R }, A) => {
|
|
131
131
|
const {
|
|
132
132
|
value: k,
|
|
133
133
|
setValue: x,
|
|
@@ -135,7 +135,7 @@ const H = L(
|
|
|
135
135
|
registerTab: v,
|
|
136
136
|
tabs: T,
|
|
137
137
|
disabled: d,
|
|
138
|
-
thumbId:
|
|
138
|
+
thumbId: w,
|
|
139
139
|
orientation: h
|
|
140
140
|
} = z("Tab"), f = k === e;
|
|
141
141
|
r.useEffect(() => {
|
|
@@ -144,7 +144,7 @@ const H = L(
|
|
|
144
144
|
t ? d.current.add(e) : d.current.delete(e);
|
|
145
145
|
}, [d, t, e]);
|
|
146
146
|
const I = (i) => {
|
|
147
|
-
if (
|
|
147
|
+
if (m == null || m(i), i.defaultPrevented) return;
|
|
148
148
|
const s = T.current, l = s.indexOf(e);
|
|
149
149
|
if (l === -1) return;
|
|
150
150
|
const V = h === "vertical" ? ["ArrowDown"] : ["ArrowRight", "ArrowDown"], _ = h === "vertical" ? ["ArrowUp"] : ["ArrowLeft", "ArrowUp"];
|
|
@@ -199,10 +199,10 @@ const H = L(
|
|
|
199
199
|
onKeyDown: I,
|
|
200
200
|
...R,
|
|
201
201
|
children: [
|
|
202
|
-
f && /* @__PURE__ */
|
|
202
|
+
f && /* @__PURE__ */ p(
|
|
203
203
|
$.span,
|
|
204
204
|
{
|
|
205
|
-
layoutId:
|
|
205
|
+
layoutId: w,
|
|
206
206
|
"aria-hidden": !0,
|
|
207
207
|
transition: M,
|
|
208
208
|
className: b(
|
|
@@ -211,19 +211,16 @@ const H = L(
|
|
|
211
211
|
)
|
|
212
212
|
}
|
|
213
213
|
),
|
|
214
|
-
/* @__PURE__ */ E("span", { className: "relative inline-flex items-center gap-1", children: [
|
|
215
|
-
|
|
216
|
-
a != null && /* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ E("span", { className: "relative inline-flex items-center gap-1.5", children: [
|
|
215
|
+
g,
|
|
216
|
+
a != null && /* @__PURE__ */ p(
|
|
217
217
|
"span",
|
|
218
218
|
{
|
|
219
219
|
className: b(
|
|
220
|
-
"tabular-nums",
|
|
221
|
-
f ? "text-action-primary-text" : "text-
|
|
220
|
+
"font-normal tabular-nums",
|
|
221
|
+
f ? "text-action-primary-text" : "text-on-white-tertiary"
|
|
222
222
|
),
|
|
223
|
-
children:
|
|
224
|
-
"· ",
|
|
225
|
-
a
|
|
226
|
-
]
|
|
223
|
+
children: a
|
|
227
224
|
}
|
|
228
225
|
)
|
|
229
226
|
] })
|
|
@@ -236,7 +233,7 @@ O.displayName = "Tab";
|
|
|
236
233
|
const q = r.forwardRef(
|
|
237
234
|
({ className: o, ...e }, t) => {
|
|
238
235
|
const { orientation: a } = z("TabSeparator");
|
|
239
|
-
return /* @__PURE__ */
|
|
236
|
+
return /* @__PURE__ */ p(
|
|
240
237
|
"span",
|
|
241
238
|
{
|
|
242
239
|
ref: t,
|
|
@@ -254,15 +251,15 @@ const q = r.forwardRef(
|
|
|
254
251
|
);
|
|
255
252
|
q.displayName = "TabSeparator";
|
|
256
253
|
const F = r.forwardRef(
|
|
257
|
-
({ className: o, value: e, children: t, ...a },
|
|
258
|
-
const { value: c, baseId:
|
|
259
|
-
return c !== e ? null : /* @__PURE__ */
|
|
254
|
+
({ className: o, value: e, children: t, ...a }, g) => {
|
|
255
|
+
const { value: c, baseId: m } = z("TabPanel");
|
|
256
|
+
return c !== e ? null : /* @__PURE__ */ p(
|
|
260
257
|
"div",
|
|
261
258
|
{
|
|
262
|
-
ref:
|
|
259
|
+
ref: g,
|
|
263
260
|
role: "tabpanel",
|
|
264
|
-
id: N(
|
|
265
|
-
"aria-labelledby": N(
|
|
261
|
+
id: N(m, "panel", e),
|
|
262
|
+
"aria-labelledby": N(m, "tab", e),
|
|
266
263
|
tabIndex: 0,
|
|
267
264
|
className: b(
|
|
268
265
|
"flex-1 outline-none focus-visible:ring-3 focus-visible:ring-ring rounded-sm",
|
|
@@ -35,6 +35,7 @@ import "react-aria-components";
|
|
|
35
35
|
import "../../components/autocomplete.js";
|
|
36
36
|
import "../../components/slider.js";
|
|
37
37
|
import "../../components/segmented.js";
|
|
38
|
+
import "../../components/filters.js";
|
|
38
39
|
import { Modal as q, ModalHeader as J, ModalTitle as Q, ModalBody as x, ModalFooter as g } from "../../components/modal.js";
|
|
39
40
|
import "../../components/drawer.js";
|
|
40
41
|
import "../../components/popover.js";
|
|
@@ -106,7 +107,7 @@ import "../../components/assistant-ui/quote.js";
|
|
|
106
107
|
import "../../components/assistant-ui/sources.js";
|
|
107
108
|
import "../../components/assistant-ui/tool-fallback.js";
|
|
108
109
|
import "../../components/assistant-ui/tool-group.js";
|
|
109
|
-
function
|
|
110
|
+
function ii({
|
|
110
111
|
block: i,
|
|
111
112
|
trigger: v = "button",
|
|
112
113
|
className: A,
|
|
@@ -358,5 +359,5 @@ function ei({
|
|
|
358
359
|
] });
|
|
359
360
|
}
|
|
360
361
|
export {
|
|
361
|
-
|
|
362
|
+
ii as AddToArtifact
|
|
362
363
|
};
|
package/examples/README.md
CHANGED
|
@@ -13,6 +13,8 @@ root in `MotionConfig`, `ToastProvider` and `TooltipProvider`.
|
|
|
13
13
|
| `agents-screen.tsx` | `AgentsScreen` | A full list page: `PageHeader` with a primary action, a summary strip, `Tabs` with counts leading a `SearchDisclosure`, a filter `Dropdown`, a sortable `Table` with clickable rows and a pinned action column, per-row actions with `Tooltip`s, and filtered `EmptyState`s. |
|
|
14
14
|
| `settings-screen.tsx` | `SettingsScreen` | A settings card: `Card` header with a status `Badge`, an `InputField`, a `SettingList` of `SettingRow`s with `Switch` and `Button` controls, and one primary action. |
|
|
15
15
|
| `workspace-header.tsx` | `WorkspaceHeaderScreen` | A page header with a status `Badge` and trailing actions, then `Tabs` with counts whose panels hold `Card`s. |
|
|
16
|
+
| `campaigns-screen.tsx` | `CampaignsScreen` | The collection-screen recipe: `BodyPageHeader` with one primary action, counted `Tabs` leading `SearchDisclosure` + `Filters`, a multi-select `Table` (hover-revealed checkboxes, cohort child rows, `isActive` open row) whose page size fills the panel with `Pagination` at the bottom, a shell-level `Drawer` with status under the title and Performance / Details sections, and the fixed-height New campaign `Modal`. |
|
|
17
|
+
| `campaign-analysis-screen.tsx` | `CampaignAnalysisScreen` | The record-analytics recipe: a 16px `Breadcrumbs` title with the primary action on the same row, record `Tabs`, outlined stat cards with `Progress`, and outlined `BarChart` / `LineChart` cards with header legends and printed values. |
|
|
16
18
|
|
|
17
19
|
```tsx
|
|
18
20
|
// app/agents/page.tsx
|
|
@@ -25,6 +27,5 @@ export default function Page() {
|
|
|
25
27
|
}
|
|
26
28
|
```
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
**Recipes**, so what you see there is what these files produce. Icons come from
|
|
30
|
+
Icons come from
|
|
30
31
|
`@actioneer/ads/lib/icons`; never install a second icon package.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Campaign analysis screen — the ADS record/analytics-page recipe, built only
|
|
3
|
+
* from ADS exports.
|
|
4
|
+
*
|
|
5
|
+
* Follows principles `leading-back-navigation`, `analytics-surfaces` and
|
|
6
|
+
* `status-language` (see `get_principles`):
|
|
7
|
+
*
|
|
8
|
+
* - The 16px Breadcrumbs trail (parent / record) IS the page title; the one
|
|
9
|
+
* primary action sits at the right end of the same row. No back arrow and
|
|
10
|
+
* no repeated H1.
|
|
11
|
+
* - Every stat and every chart sits in its own outlined card (1px WG3 border,
|
|
12
|
+
* radius-l, 20px padding, flat), 16px apart.
|
|
13
|
+
* - A stat card stacks label → number + scope 4px apart, then a Progress bar
|
|
14
|
+
* 12px below that fills the card.
|
|
15
|
+
* - A chart card puts its title + scope subtitle on the left and the legend at
|
|
16
|
+
* the right of the same row (`legendPlacement="header"`), and prints its
|
|
17
|
+
* values on the chart — never hover-only.
|
|
18
|
+
*
|
|
19
|
+
* Copy it and replace the sample STATS / SEGMENT / REACH data with your own.
|
|
20
|
+
*/
|
|
21
|
+
import * as React from "react";
|
|
22
|
+
import {
|
|
23
|
+
BarChart,
|
|
24
|
+
BreadcrumbItem,
|
|
25
|
+
Breadcrumbs,
|
|
26
|
+
Button,
|
|
27
|
+
LineChart,
|
|
28
|
+
Progress,
|
|
29
|
+
Tab,
|
|
30
|
+
TabList,
|
|
31
|
+
Tabs,
|
|
32
|
+
} from "@actioneer/ads";
|
|
33
|
+
|
|
34
|
+
export const STATS = [
|
|
35
|
+
{ label: "Calls analysed", value: 3930, of: "of 4,800 calls", percent: 82, color: "primary" as const },
|
|
36
|
+
{ label: "Recipients reached", value: 864, of: "of 4,800 people", percent: 18, color: "primary" as const },
|
|
37
|
+
// The one number that needs attention is the only amber one.
|
|
38
|
+
{ label: "Asked for a callback", value: 144, of: "of 864 calls", percent: 17, color: "warning" as const },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export const SEGMENT = [
|
|
42
|
+
{ day: "Oct 19", netNew: 3200, already: 1900 },
|
|
43
|
+
{ day: "Oct 20", netNew: 420, already: 3080 },
|
|
44
|
+
{ day: "Oct 21", netNew: 360, already: 3240 },
|
|
45
|
+
{ day: "Oct 22", netNew: 440, already: 3460 },
|
|
46
|
+
{ day: "Oct 23", netNew: 380, already: 3520 },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export const REACH = [
|
|
50
|
+
{ day: "Oct 19", reached: 12, booked: 2 },
|
|
51
|
+
{ day: "Oct 20", reached: 14, booked: 3 },
|
|
52
|
+
{ day: "Oct 21", reached: 15, booked: 4 },
|
|
53
|
+
{ day: "Oct 22", reached: 17, booked: 4 },
|
|
54
|
+
{ day: "Oct 23", reached: 18, booked: 5 },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const TABS = ["Script", "Workflow", "Analysis", "Call logs", "Guardrails"];
|
|
58
|
+
|
|
59
|
+
/** Outlined container for one stat or one chart (principle `analytics-surfaces`). */
|
|
60
|
+
function DataCard({ children, label }: { children: React.ReactNode; label: string }) {
|
|
61
|
+
return (
|
|
62
|
+
<section aria-label={label} className="flex min-w-0 flex-col rounded-l border border-tertiary bg-card p-5">
|
|
63
|
+
{children}
|
|
64
|
+
</section>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function CampaignAnalysisScreen() {
|
|
69
|
+
const [tab, setTab] = React.useState("Analysis");
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className="flex h-screen bg-background p-3 text-foreground">
|
|
73
|
+
<main aria-label="Q4 renewal reminders" className="flex min-w-0 flex-1 flex-col overflow-hidden rounded-l bg-card">
|
|
74
|
+
<div className="px-6 pt-6">
|
|
75
|
+
<Breadcrumbs actions={<Button>Pause campaign</Button>}>
|
|
76
|
+
<BreadcrumbItem href="#campaigns">Voice campaigns</BreadcrumbItem>
|
|
77
|
+
<BreadcrumbItem isCurrent>Q4 renewal reminders</BreadcrumbItem>
|
|
78
|
+
</Breadcrumbs>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div className="px-6 pt-5">
|
|
82
|
+
<Tabs value={tab} onValueChange={setTab}>
|
|
83
|
+
<TabList aria-label="Campaign sections">
|
|
84
|
+
{TABS.map((item) => (
|
|
85
|
+
<Tab key={item} value={item}>{item}</Tab>
|
|
86
|
+
))}
|
|
87
|
+
</TabList>
|
|
88
|
+
</Tabs>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-6 pt-6 pb-6">
|
|
92
|
+
<div role="list" aria-label="Campaign progress" className="grid grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] gap-4">
|
|
93
|
+
{STATS.map((stat) => (
|
|
94
|
+
<div role="listitem" key={stat.label} className="contents">
|
|
95
|
+
<DataCard label={stat.label}>
|
|
96
|
+
<p className="text-m text-secondary">{stat.label}</p>
|
|
97
|
+
<p className="mt-1 flex items-baseline gap-2">
|
|
98
|
+
<span className="text-3xl tabular-nums text-foreground">{stat.value.toLocaleString("en-IN")}</span>
|
|
99
|
+
<span className="text-m text-secondary">{stat.of}</span>
|
|
100
|
+
</p>
|
|
101
|
+
<Progress className="mt-3" value={stat.percent} color={stat.color} label={stat.label} />
|
|
102
|
+
</DataCard>
|
|
103
|
+
</div>
|
|
104
|
+
))}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div className="grid grid-cols-[repeat(auto-fill,minmax(24rem,1fr))] gap-4">
|
|
108
|
+
<DataCard label="Who was in the segment">
|
|
109
|
+
<BarChart
|
|
110
|
+
title="Who was in the segment"
|
|
111
|
+
subtitle="4,800 net new numbers · Oct 19 – 23"
|
|
112
|
+
legendPlacement="header"
|
|
113
|
+
data={SEGMENT}
|
|
114
|
+
categoryKey="day"
|
|
115
|
+
series={["netNew", "already"]}
|
|
116
|
+
seriesLabels={{ netNew: "Net new", already: "Already in campaign" }}
|
|
117
|
+
stacked
|
|
118
|
+
height={360}
|
|
119
|
+
/>
|
|
120
|
+
</DataCard>
|
|
121
|
+
<DataCard label="Did we reach them?">
|
|
122
|
+
<LineChart
|
|
123
|
+
title="Did we reach them?"
|
|
124
|
+
subtitle="Share of 4,800 people · by day"
|
|
125
|
+
legendPlacement="header"
|
|
126
|
+
data={REACH}
|
|
127
|
+
categoryKey="day"
|
|
128
|
+
series={["reached", "booked"]}
|
|
129
|
+
seriesLabels={{ reached: "Reached", booked: "Booked" }}
|
|
130
|
+
height={360}
|
|
131
|
+
/>
|
|
132
|
+
</DataCard>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</main>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|