@agentero/design-system 0.5.1 → 0.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.
@@ -0,0 +1,324 @@
1
+ import { ReactNode } from 'react';
2
+ import { toast as sonnerToast } from 'sonner';
3
+ import { VariantProps } from 'tailwind-variants';
4
+ /**
5
+ * Style recipe for Toast using tailwind-variants. Multi-slot recipe whose
6
+ * variants (`layout`, `type`) drive the two layout treatments (`inline`,
7
+ * `expanded`) across the five semantic toast types. Compound variants paint
8
+ * the colored left rail that distinguishes the expanded layout per type.
9
+ *
10
+ * Exported for advanced composition (e.g., styling a custom element to match
11
+ * a Toast slot). Prefer rendering the `Toast` provider + calling `toast()`.
12
+ *
13
+ * @summary tailwind-variants recipe backing the Toast component styles
14
+ */
15
+ export declare const toastRecipe: import('tailwind-variants').TVReturnType<{
16
+ layout: {
17
+ inline: {
18
+ root: string;
19
+ iconWrapper: string;
20
+ contentWrapper: string;
21
+ leading: string;
22
+ trailing: string;
23
+ };
24
+ expanded: {
25
+ root: string;
26
+ iconWrapper: string;
27
+ contentWrapper: string;
28
+ leading: string;
29
+ trailing: string;
30
+ };
31
+ };
32
+ type: {
33
+ neutral: {
34
+ icon: string;
35
+ };
36
+ success: {
37
+ icon: string;
38
+ };
39
+ error: {
40
+ icon: string;
41
+ };
42
+ warning: {
43
+ icon: string;
44
+ };
45
+ info: {
46
+ icon: string;
47
+ };
48
+ };
49
+ }, {
50
+ root: string;
51
+ iconWrapper: string;
52
+ icon: string;
53
+ contentWrapper: string;
54
+ leading: string;
55
+ title: string;
56
+ description: string;
57
+ trailing: string;
58
+ actionBtn: string;
59
+ }, undefined, {
60
+ layout: {
61
+ inline: {
62
+ root: string;
63
+ iconWrapper: string;
64
+ contentWrapper: string;
65
+ leading: string;
66
+ trailing: string;
67
+ };
68
+ expanded: {
69
+ root: string;
70
+ iconWrapper: string;
71
+ contentWrapper: string;
72
+ leading: string;
73
+ trailing: string;
74
+ };
75
+ };
76
+ type: {
77
+ neutral: {
78
+ icon: string;
79
+ };
80
+ success: {
81
+ icon: string;
82
+ };
83
+ error: {
84
+ icon: string;
85
+ };
86
+ warning: {
87
+ icon: string;
88
+ };
89
+ info: {
90
+ icon: string;
91
+ };
92
+ };
93
+ }, {
94
+ root: string;
95
+ iconWrapper: string;
96
+ icon: string;
97
+ contentWrapper: string;
98
+ leading: string;
99
+ title: string;
100
+ description: string;
101
+ trailing: string;
102
+ actionBtn: string;
103
+ }, import('tailwind-variants').TVReturnType<{
104
+ layout: {
105
+ inline: {
106
+ root: string;
107
+ iconWrapper: string;
108
+ contentWrapper: string;
109
+ leading: string;
110
+ trailing: string;
111
+ };
112
+ expanded: {
113
+ root: string;
114
+ iconWrapper: string;
115
+ contentWrapper: string;
116
+ leading: string;
117
+ trailing: string;
118
+ };
119
+ };
120
+ type: {
121
+ neutral: {
122
+ icon: string;
123
+ };
124
+ success: {
125
+ icon: string;
126
+ };
127
+ error: {
128
+ icon: string;
129
+ };
130
+ warning: {
131
+ icon: string;
132
+ };
133
+ info: {
134
+ icon: string;
135
+ };
136
+ };
137
+ }, {
138
+ root: string;
139
+ iconWrapper: string;
140
+ icon: string;
141
+ contentWrapper: string;
142
+ leading: string;
143
+ title: string;
144
+ description: string;
145
+ trailing: string;
146
+ actionBtn: string;
147
+ }, undefined, unknown, unknown, undefined>>;
148
+ type ToastVariants = VariantProps<typeof toastRecipe>;
149
+ /**
150
+ * Semantic type of a toast notification. Drives the built-in icon and the
151
+ * color applied to the expanded-layout left rail.
152
+ *
153
+ * @summary Toast semantic type union (`neutral`, `success`, `error`, `warning`, `info`)
154
+ */
155
+ export type ToastType = NonNullable<ToastVariants['type']>;
156
+ /** Structured action with a label and click handler, rendered as a secondary Button. */
157
+ type ToastActionObject = {
158
+ label: ReactNode;
159
+ onClick: () => void;
160
+ };
161
+ /**
162
+ * Trailing action rendered next to the title. Pass `{ label, onClick }` for
163
+ * the built-in secondary Button, or any ReactNode to render a custom control.
164
+ *
165
+ * @summary Toast action — structured object or raw ReactNode
166
+ */
167
+ export type ToastAction = ToastActionObject | ReactNode;
168
+ /**
169
+ * Options passed to {@link toast} and its typed helpers. Controls the toast's
170
+ * content, layout, trailing actions, auto-dismiss duration, and id.
171
+ *
172
+ * @summary Options for the imperative `toast()` API
173
+ */
174
+ export type ToastOptions = {
175
+ /** Optional secondary text shown below the title. */
176
+ description?: ReactNode;
177
+ /**
178
+ * Layout variant. Defaults to `'inline'`.
179
+ * - `'inline'` — compact single-line layout.
180
+ * - `'expanded'` — multi-line layout with a colored left rail.
181
+ */
182
+ variant?: 'inline' | 'expanded';
183
+ /** Custom icon that overrides the default type-based icon. */
184
+ icon?: ReactNode;
185
+ /**
186
+ * Optional primary action rendered in the trailing area. Pass
187
+ * `{ label, onClick }` for the built-in secondary Button, or any ReactNode
188
+ * for a custom control.
189
+ */
190
+ action?: ToastAction;
191
+ /** Optional cancel button rendered alongside `action`. */
192
+ cancel?: {
193
+ label: ReactNode;
194
+ onClick: () => void;
195
+ };
196
+ /** Auto-dismiss duration in milliseconds. Overrides the `Toast` provider default. */
197
+ duration?: number;
198
+ /** Explicit toast id — useful for deduplication or programmatic dismissal via `toast.dismiss(id)`. */
199
+ id?: string | number;
200
+ /** Additional className merged onto the root element. Escape hatch — prefer `variant` and `type` for style decisions. */
201
+ className?: string;
202
+ /** Whether to show the dismiss (close) button. Defaults to `true`. */
203
+ dismissible?: boolean;
204
+ };
205
+ /**
206
+ * Imperative API for showing toast notifications. Calling `toast(title)`
207
+ * fires a neutral toast; the typed helpers (`toast.success`, `toast.error`,
208
+ * `toast.warning`, `toast.info`) apply the matching semantic icon and color.
209
+ *
210
+ * `toast.dismiss(id?)` dismisses a specific toast (or all of them when called
211
+ * without an id); `toast.loading` + `toast.promise` wire to sonner's async
212
+ * helpers; `toast.custom` is an escape hatch for fully-custom render output —
213
+ * reach for the typed helpers first.
214
+ *
215
+ * Requires a `<Toast />` provider mounted somewhere in the React tree.
216
+ *
217
+ * @summary Imperative `toast()` with typed semantic helpers and async utilities
218
+ *
219
+ * @example
220
+ * toast('Something happened');
221
+ *
222
+ * @example
223
+ * toast.success('Policy saved');
224
+ * toast.error('Save failed');
225
+ * toast.warning('License expiring soon');
226
+ * toast.info('Sync in progress');
227
+ *
228
+ * @example
229
+ * toast.error('Upload failed', {
230
+ * variant: 'expanded',
231
+ * description: 'The file could not be processed.',
232
+ * action: { label: 'Retry', onClick: retry }
233
+ * });
234
+ *
235
+ * @example
236
+ * const id = toast.info('Uploading...');
237
+ * toast.dismiss(id);
238
+ *
239
+ * @example
240
+ * toast.promise(saveDocument(), {
241
+ * loading: 'Saving...',
242
+ * success: 'Saved',
243
+ * error: 'Save failed'
244
+ * });
245
+ */
246
+ type TypedToastFn = (title: ReactNode, options?: ToastOptions) => string | number;
247
+ type ToastApi = TypedToastFn & {
248
+ success: TypedToastFn;
249
+ error: TypedToastFn;
250
+ warning: TypedToastFn;
251
+ info: TypedToastFn;
252
+ dismiss: typeof sonnerToast.dismiss;
253
+ custom: typeof sonnerToast.custom;
254
+ loading: typeof sonnerToast.loading;
255
+ promise: typeof sonnerToast.promise;
256
+ };
257
+ export declare const toast: ToastApi;
258
+ /**
259
+ * Placement of the Toaster on the screen. Mirrors sonner's `position` prop.
260
+ *
261
+ * @summary Toaster screen position union
262
+ */
263
+ export type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
264
+ /**
265
+ * Props for the `Toast` provider. Exposes the sonner `Toaster` configuration
266
+ * surface the design system documents directly (`position`, `duration`,
267
+ * `className`, `dir`, `gap`, `offset`, `expand`, `visibleToasts`, `hotkey`,
268
+ * `richColors`, `invert`). Any additional props are forwarded to sonner via
269
+ * the underlying `<Toaster>` component.
270
+ *
271
+ * @summary Props accepted by the Toast provider
272
+ */
273
+ export type ToastProps = {
274
+ /** Placement of the toaster on the screen. Defaults to `'bottom-right'`. */
275
+ position?: ToastPosition;
276
+ /** Default auto-dismiss duration in ms for toasts fired against this provider. Defaults to `5000`. */
277
+ duration?: number;
278
+ /** Text direction. Sonner forwards this to the rendered toaster root. */
279
+ dir?: 'auto' | 'ltr' | 'rtl';
280
+ /** Gap between stacked toasts, in pixels. */
281
+ gap?: number;
282
+ /** Offset from the screen edge, in pixels or as a CSS length. */
283
+ offset?: string | number;
284
+ /** When `true`, stack expands on hover instead of auto-collapsing. */
285
+ expand?: boolean;
286
+ /** Maximum number of toasts rendered at once before earlier ones dismiss. */
287
+ visibleToasts?: number;
288
+ /** Keyboard shortcut used to focus the toaster. */
289
+ hotkey?: string[];
290
+ /** When `true`, sonner paints colored backgrounds per type (DS uses its own icon tokens by default). */
291
+ richColors?: boolean;
292
+ /** When `true`, flips light/dark theme on the toaster root. */
293
+ invert?: boolean;
294
+ /** Additional className merged onto the sonner `<Toaster>` root. */
295
+ className?: string;
296
+ };
297
+ /**
298
+ * Toast provider. Renders the sonner `<Toaster />` configured for the
299
+ * {@link toast} imperative API. Mount it once near the root of your React
300
+ * tree (below any context providers that the toasts need, and above the
301
+ * rest of the app) so every call to `toast()` from anywhere in the tree
302
+ * renders into the same surface.
303
+ *
304
+ * Defaults: `position='bottom-right'`, `duration=5000`. The Toaster is sized
305
+ * to `23.75rem` (`[--width:23.75rem]`) and each list item stretches to that
306
+ * width (`[&>li]:w-full`) so the DS Toast fills the Toaster row rather than
307
+ * sonner's 356px default. The provider disables sonner's built-in close
308
+ * button (`closeButton={false}`) — dismissal is rendered inside each Toast
309
+ * by the DS component itself.
310
+ *
311
+ * Do **not** use Toast for persistent feedback — mount an `Alert` with
312
+ * `color="success|danger"` instead. Do **not** use Toast for form
313
+ * validation errors — render those inline with the form field.
314
+ *
315
+ * @summary Toast provider; mount once near the app root
316
+ *
317
+ * @example
318
+ * <Toast />
319
+ *
320
+ * @example
321
+ * <Toast position="top-center" duration={4000} />
322
+ */
323
+ export declare const Toast: ({ position, duration, className, ...props }: ToastProps) => import("react/jsx-runtime").JSX.Element;
324
+ export {};
@@ -0,0 +1,163 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import { Button as t } from "../button/button.js";
4
+ import { IconCheckCircle as n, IconCloseSmall as r, IconErrorOutline as i, IconInfoFilled as a, IconWarning as o } from "./icons.js";
5
+ import { tv as s } from "tailwind-variants";
6
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import { Toaster as u, toast as d } from "sonner";
8
+ //#region src/toast/toast.tsx
9
+ var f = s({
10
+ slots: {
11
+ root: "w-full flex items-start border border-border-default-base-primary bg-white text-text-default-base-primary shadow-xs",
12
+ iconWrapper: "shrink-0",
13
+ icon: "size-6 [&_svg]:size-6 [&_path]:fill-current",
14
+ contentWrapper: "flex flex-1 min-w-0",
15
+ leading: "flex flex-1 min-w-0 text-sm leading-normal",
16
+ title: "font-semibold text-text-default-base-primary shrink-0",
17
+ description: "font-normal text-text-default-base-tertiary",
18
+ trailing: "flex items-center gap-2",
19
+ actionBtn: "min-w-0 shadow-xs"
20
+ },
21
+ variants: {
22
+ layout: {
23
+ inline: {
24
+ root: "rounded-lg p-2 gap-2 items-center",
25
+ iconWrapper: "pl-1",
26
+ contentWrapper: "flex-row items-center gap-0",
27
+ leading: "flex-col items-start gap-0",
28
+ trailing: "pl-2"
29
+ },
30
+ expanded: {
31
+ root: "rounded-md p-4 gap-1 [background-size:0.375rem_100%] bg-left bg-no-repeat",
32
+ iconWrapper: "-mt-px",
33
+ contentWrapper: "flex-col items-start gap-3",
34
+ leading: "flex-col items-start gap-0 px-2",
35
+ trailing: "px-2"
36
+ }
37
+ },
38
+ type: {
39
+ neutral: { icon: "text-icon-default-base-secondary" },
40
+ success: { icon: "text-icon-default-positive-primary" },
41
+ error: { icon: "text-icon-default-danger-primary" },
42
+ warning: { icon: "text-icon-default-warning-primary" },
43
+ info: { icon: "text-icon-default-info-primary" }
44
+ }
45
+ },
46
+ compoundVariants: [
47
+ {
48
+ layout: "expanded",
49
+ type: "neutral",
50
+ class: { root: "bg-[linear-gradient(var(--color-rail-neutral),var(--color-rail-neutral))]" }
51
+ },
52
+ {
53
+ layout: "expanded",
54
+ type: "success",
55
+ class: { root: "bg-[linear-gradient(var(--color-rail-success),var(--color-rail-success))]" }
56
+ },
57
+ {
58
+ layout: "expanded",
59
+ type: "error",
60
+ class: { root: "bg-[linear-gradient(var(--color-rail-danger),var(--color-rail-danger))]" }
61
+ },
62
+ {
63
+ layout: "expanded",
64
+ type: "warning",
65
+ class: { root: "bg-[linear-gradient(var(--color-rail-warning),var(--color-rail-warning))]" }
66
+ },
67
+ {
68
+ layout: "expanded",
69
+ type: "info",
70
+ class: { root: "bg-[linear-gradient(var(--color-rail-info),var(--color-rail-info))]" }
71
+ }
72
+ ],
73
+ defaultVariants: {
74
+ layout: "inline",
75
+ type: "neutral"
76
+ }
77
+ }), p = (e) => typeof e == "object" && !!e && "onClick" in e, m = {
78
+ neutral: /* @__PURE__ */ c(a, {}),
79
+ success: /* @__PURE__ */ c(n, {}),
80
+ info: /* @__PURE__ */ c(a, {}),
81
+ warning: /* @__PURE__ */ c(o, {}),
82
+ error: /* @__PURE__ */ c(i, {})
83
+ }, h = ({ id: n, title: i, type: a = "neutral", variant: o = "inline", icon: s, description: u, action: h, cancel: g, className: _, dismissible: v = !0 }) => {
84
+ let y = f({
85
+ layout: o,
86
+ type: a
87
+ });
88
+ return /* @__PURE__ */ l("div", {
89
+ "data-slot": "toast",
90
+ className: e(y.root(), _),
91
+ children: [
92
+ /* @__PURE__ */ c("div", {
93
+ className: y.iconWrapper(),
94
+ children: /* @__PURE__ */ c("span", {
95
+ className: y.icon(),
96
+ children: s ?? m[a]
97
+ })
98
+ }),
99
+ /* @__PURE__ */ l("div", {
100
+ className: y.contentWrapper(),
101
+ children: [/* @__PURE__ */ l("div", {
102
+ className: y.leading(),
103
+ children: [i && /* @__PURE__ */ c("h2", {
104
+ className: y.title(),
105
+ children: i
106
+ }), u && /* @__PURE__ */ c("p", {
107
+ className: y.description(),
108
+ children: u
109
+ })]
110
+ }), (h || g) && /* @__PURE__ */ l("div", {
111
+ className: y.trailing(),
112
+ children: [h && (p(h) ? /* @__PURE__ */ c(t, {
113
+ variant: "secondary",
114
+ className: y.actionBtn(),
115
+ onClick: () => {
116
+ h.onClick(), d.dismiss(n);
117
+ },
118
+ children: h.label
119
+ }) : h), g && /* @__PURE__ */ c(t, {
120
+ variant: "ghost",
121
+ onClick: () => {
122
+ g.onClick(), d.dismiss(n);
123
+ },
124
+ children: g.label
125
+ })]
126
+ })]
127
+ }),
128
+ v && /* @__PURE__ */ c(t, {
129
+ onClick: () => d.dismiss(n),
130
+ "aria-label": "Close",
131
+ variant: "ghost",
132
+ iconOnly: !0,
133
+ children: /* @__PURE__ */ c(r, {})
134
+ })
135
+ ]
136
+ });
137
+ }, g = (e, t, n) => {
138
+ let { duration: r, id: i, className: a, ...o } = n ?? {}, s = {};
139
+ return r !== void 0 && (s.duration = r), i !== void 0 && (s.id = i), d.custom((n) => /* @__PURE__ */ c(h, {
140
+ id: n,
141
+ title: e,
142
+ type: t,
143
+ className: a,
144
+ ...o
145
+ }), s);
146
+ }, _ = Object.assign((e, t) => g(e, void 0, t), {
147
+ success: (e, t) => g(e, "success", t),
148
+ error: (e, t) => g(e, "error", t),
149
+ warning: (e, t) => g(e, "warning", t),
150
+ info: (e, t) => g(e, "info", t),
151
+ dismiss: d.dismiss,
152
+ custom: d.custom,
153
+ loading: d.loading,
154
+ promise: d.promise
155
+ }), v = ({ position: t = "bottom-right", duration: n = 5e3, className: r, ...i }) => /* @__PURE__ */ c(u, {
156
+ ...i,
157
+ position: t,
158
+ duration: n,
159
+ closeButton: !1,
160
+ className: e("[--width:23.75rem]! [&>li]:w-full", r)
161
+ });
162
+ //#endregion
163
+ export { v as Toast, _ as toast, f as toastRecipe };
package/theme/base.css CHANGED
@@ -385,6 +385,8 @@
385
385
 
386
386
  --color-border-default-disable-primary: var(--color-slate-100);
387
387
 
388
+ --color-border-menu-divider: #ebebef;
389
+
388
390
  /* Text Tokens */
389
391
  --color-text-input-normal: var(--color-slate-800);
390
392
  --color-text-input-disable: var(--color-slate-300);
@@ -659,6 +661,21 @@
659
661
  --color-icon-alert-ghost-dynamic: var(--color-orange-700);
660
662
  --color-icon-alert-ghost-playful: var(--color-pink-600);
661
663
 
664
+ /* ========================================
665
+ * TOAST
666
+ * ======================================== */
667
+
668
+ /* Rail — colored left strip painted on expanded-layout toasts */
669
+ --color-rail-neutral: var(--color-neutrals-200);
670
+ --color-rail-success: var(--color-positive-500);
671
+ --color-rail-danger: var(--color-danger-500);
672
+ --color-rail-warning: var(--color-warning-500);
673
+ --color-rail-info: var(--color-blue-600);
674
+
675
+ /* Focus Ring */
676
+ --color-focus-ring-button-primary: var(--color-slate-800);
677
+ --color-focus-ring-button-destructive: var(--color-danger-500);
678
+
662
679
  /* ========================================
663
680
  * STATUS BALL
664
681
  * ======================================== */
@@ -743,6 +760,12 @@
743
760
  --animate-cmd-content-in: cmd-content-in 200ms cubic-bezier(0.23, 1, 0.32, 1);
744
761
  --animate-cmd-content-out: cmd-content-out 150ms ease-in forwards;
745
762
  --animate-fade-in: fadeIn 0.3s forwards;
763
+ --animate-dropdown-slide-in: dropdownSlideIn 200ms ease-out;
764
+ --animate-dropdown-slide-out: dropdownSlideOut 150ms ease-in;
765
+ --animate-dropdown-slide-in-from-top: dropdownSlideInFromTop 200ms ease-out;
766
+ --animate-dropdown-slide-in-from-bottom: dropdownSlideInFromBottom 200ms ease-out;
767
+ --animate-dropdown-slide-in-from-left: dropdownSlideInFromLeft 200ms ease-out;
768
+ --animate-dropdown-slide-in-from-right: dropdownSlideInFromRight 200ms ease-out;
746
769
 
747
770
  /* ========================================
748
771
  * Z-INDEX
@@ -858,6 +881,72 @@
858
881
  }
859
882
  }
860
883
 
884
+ @keyframes dropdownSlideIn {
885
+ 0% {
886
+ opacity: 0;
887
+ transform: scale(0.9);
888
+ }
889
+ 100% {
890
+ opacity: 1;
891
+ transform: scale(1);
892
+ }
893
+ }
894
+
895
+ @keyframes dropdownSlideOut {
896
+ 0% {
897
+ opacity: 1;
898
+ transform: scale(1);
899
+ }
900
+ 100% {
901
+ opacity: 0;
902
+ transform: scale(0.9);
903
+ }
904
+ }
905
+
906
+ @keyframes dropdownSlideInFromTop {
907
+ 0% {
908
+ opacity: 0;
909
+ transform: translateY(-0.5rem) scale(0.9);
910
+ }
911
+ 100% {
912
+ opacity: 1;
913
+ transform: translateY(0) scale(1);
914
+ }
915
+ }
916
+
917
+ @keyframes dropdownSlideInFromBottom {
918
+ 0% {
919
+ opacity: 0;
920
+ transform: translateY(0.5rem) scale(0.9);
921
+ }
922
+ 100% {
923
+ opacity: 1;
924
+ transform: translateY(0) scale(1);
925
+ }
926
+ }
927
+
928
+ @keyframes dropdownSlideInFromLeft {
929
+ 0% {
930
+ opacity: 0;
931
+ transform: translateX(-0.5rem) scale(0.9);
932
+ }
933
+ 100% {
934
+ opacity: 1;
935
+ transform: translateX(0) scale(1);
936
+ }
937
+ }
938
+
939
+ @keyframes dropdownSlideInFromRight {
940
+ 0% {
941
+ opacity: 0;
942
+ transform: translateX(0.5rem) scale(0.9);
943
+ }
944
+ 100% {
945
+ opacity: 1;
946
+ transform: translateX(0) scale(1);
947
+ }
948
+ }
949
+
861
950
  html {
862
951
  /* body.md textStyle from Panda → text-base */
863
952
  font-size: var(--text-base);