@handled-ai/design-system 0.9.28 → 0.11.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.
Files changed (74) hide show
  1. package/dist/components/account-contacts-popover.d.ts +22 -0
  2. package/dist/components/account-contacts-popover.js +180 -0
  3. package/dist/components/account-contacts-popover.js.map +1 -0
  4. package/dist/components/badge.d.ts +1 -1
  5. package/dist/components/button.d.ts +2 -2
  6. package/dist/components/compliance-badge.d.ts +10 -0
  7. package/dist/components/compliance-badge.js +95 -0
  8. package/dist/components/compliance-badge.js.map +1 -0
  9. package/dist/components/contact-chip.d.ts +12 -0
  10. package/dist/components/contact-chip.js +98 -0
  11. package/dist/components/contact-chip.js.map +1 -0
  12. package/dist/components/draft-feedback-inline.d.ts +11 -0
  13. package/dist/components/draft-feedback-inline.js +153 -0
  14. package/dist/components/draft-feedback-inline.js.map +1 -0
  15. package/dist/components/empty-state.d.ts +11 -0
  16. package/dist/components/empty-state.js +46 -0
  17. package/dist/components/empty-state.js.map +1 -0
  18. package/dist/components/filter-chip.d.ts +9 -0
  19. package/dist/components/filter-chip.js +67 -0
  20. package/dist/components/filter-chip.js.map +1 -0
  21. package/dist/components/inline-banner.d.ts +10 -0
  22. package/dist/components/inline-banner.js +97 -0
  23. package/dist/components/inline-banner.js.map +1 -0
  24. package/dist/components/kbd-hint.d.ts +5 -0
  25. package/dist/components/kbd-hint.js +51 -0
  26. package/dist/components/kbd-hint.js.map +1 -0
  27. package/dist/components/rich-text-toolbar.d.ts +9 -0
  28. package/dist/components/rich-text-toolbar.js +103 -0
  29. package/dist/components/rich-text-toolbar.js.map +1 -0
  30. package/dist/components/step-timeline.d.ts +19 -0
  31. package/dist/components/step-timeline.js +134 -0
  32. package/dist/components/step-timeline.js.map +1 -0
  33. package/dist/components/sticky-action-bar.d.ts +10 -0
  34. package/dist/components/sticky-action-bar.js +56 -0
  35. package/dist/components/sticky-action-bar.js.map +1 -0
  36. package/dist/components/suggested-actions.js +2 -304
  37. package/dist/components/suggested-actions.js.map +1 -1
  38. package/dist/components/switch.d.ts +6 -0
  39. package/dist/components/switch.js +66 -0
  40. package/dist/components/switch.js.map +1 -0
  41. package/dist/components/variable-autocomplete.d.ts +21 -0
  42. package/dist/components/variable-autocomplete.js +171 -0
  43. package/dist/components/variable-autocomplete.js.map +1 -0
  44. package/dist/index.d.ts +14 -1
  45. package/dist/index.js +17 -1
  46. package/dist/index.js.map +1 -1
  47. package/package.json +2 -1
  48. package/src/components/__tests__/compliance-badge.test.tsx +88 -0
  49. package/src/components/__tests__/contact-chip.test.tsx +88 -0
  50. package/src/components/__tests__/empty-state.test.tsx +76 -0
  51. package/src/components/__tests__/filter-chip.test.tsx +73 -0
  52. package/src/components/__tests__/inline-banner.test.tsx +110 -0
  53. package/src/components/__tests__/kbd-hint.test.tsx +29 -0
  54. package/src/components/__tests__/rich-text-toolbar.test.tsx +92 -0
  55. package/src/components/__tests__/step-timeline.test.tsx +174 -0
  56. package/src/components/__tests__/sticky-action-bar.test.tsx +52 -0
  57. package/src/components/__tests__/switch.test.tsx +39 -0
  58. package/src/components/__tests__/variable-autocomplete.test.tsx +155 -0
  59. package/src/components/account-contacts-popover.tsx +192 -0
  60. package/src/components/compliance-badge.tsx +68 -0
  61. package/src/components/contact-chip.tsx +68 -0
  62. package/src/components/draft-feedback-inline.tsx +193 -0
  63. package/src/components/empty-state.tsx +37 -0
  64. package/src/components/filter-chip.tsx +37 -0
  65. package/src/components/inline-banner.tsx +69 -0
  66. package/src/components/kbd-hint.tsx +21 -0
  67. package/src/components/rich-text-toolbar.tsx +90 -0
  68. package/src/components/step-timeline.tsx +149 -0
  69. package/src/components/sticky-action-bar.tsx +36 -0
  70. package/src/components/suggested-actions.tsx +2 -363
  71. package/src/components/switch.tsx +29 -0
  72. package/src/components/variable-autocomplete.tsx +178 -0
  73. package/src/index.ts +16 -1
  74. package/src/styles/globals.css +60 -0
@@ -0,0 +1,19 @@
1
+ import * as React from 'react';
2
+
3
+ type StepType = "email" | "call" | "task" | "wait" | (string & {});
4
+ interface TimelineStep {
5
+ id: string;
6
+ type: StepType;
7
+ label: string;
8
+ }
9
+ interface StepTimelineProps extends React.HTMLAttributes<HTMLDivElement> {
10
+ steps: TimelineStep[];
11
+ expandedStepId?: string;
12
+ onStepClick?: (stepId: string) => void;
13
+ onInsert?: (index: number) => void;
14
+ renderStepBody?: (step: TimelineStep) => React.ReactNode;
15
+ renderStepAccessory?: (step: TimelineStep) => React.ReactNode;
16
+ }
17
+ declare function StepTimeline({ steps, expandedStepId, onStepClick, onInsert, renderStepBody, renderStepAccessory, className, ...rest }: StepTimelineProps): React.JSX.Element;
18
+
19
+ export { StepTimeline, type StepTimelineProps, type StepType, type TimelineStep };
@@ -0,0 +1,134 @@
1
+ "use client"
2
+
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __defProps = Object.defineProperties;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __objRest = (source, exclude) => {
24
+ var target = {};
25
+ for (var prop in source)
26
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
27
+ target[prop] = source[prop];
28
+ if (source != null && __getOwnPropSymbols)
29
+ for (var prop of __getOwnPropSymbols(source)) {
30
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
31
+ target[prop] = source[prop];
32
+ }
33
+ return target;
34
+ };
35
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
36
+ import * as React from "react";
37
+ import { Mail, Phone, CheckSquare, Clock, Circle, ChevronUp, ChevronDown } from "lucide-react";
38
+ import { cn } from "../lib/utils.js";
39
+ const stepTypeConfig = {
40
+ email: { icon: Mail, classes: "bg-blue-500/10 text-blue-600" },
41
+ call: { icon: Phone, classes: "bg-emerald-500/10 text-emerald-600" },
42
+ task: { icon: CheckSquare, classes: "bg-purple-500/10 text-purple-600" },
43
+ wait: { icon: Clock, classes: "bg-muted text-muted-foreground" }
44
+ };
45
+ const defaultStepConfig = { icon: Circle, classes: "bg-muted text-muted-foreground" };
46
+ function StepTimeline(_a) {
47
+ var _b = _a, {
48
+ steps,
49
+ expandedStepId,
50
+ onStepClick,
51
+ onInsert,
52
+ renderStepBody,
53
+ renderStepAccessory,
54
+ className
55
+ } = _b, rest = __objRest(_b, [
56
+ "steps",
57
+ "expandedStepId",
58
+ "onStepClick",
59
+ "onInsert",
60
+ "renderStepBody",
61
+ "renderStepAccessory",
62
+ "className"
63
+ ]);
64
+ return /* @__PURE__ */ jsxs("div", __spreadProps(__spreadValues({ "data-slot": "step-timeline", className: cn("relative ml-5", className) }, rest), { children: [
65
+ /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-0 bottom-0 border-l-2 border-border" }),
66
+ steps.map((step, index) => {
67
+ var _a2;
68
+ const expanded = step.id === expandedStepId;
69
+ const config = (_a2 = stepTypeConfig[step.type]) != null ? _a2 : defaultStepConfig;
70
+ const TypeIcon = config.icon;
71
+ const isInteractive = !!(onStepClick || renderStepBody);
72
+ const bodyId = `step-timeline-body-${step.id}`;
73
+ const headerContent = /* @__PURE__ */ jsxs(Fragment, { children: [
74
+ /* @__PURE__ */ jsx("div", { className: cn("w-8 h-8 rounded-full flex items-center justify-center shrink-0", config.classes), children: /* @__PURE__ */ jsx(TypeIcon, { size: 16 }) }),
75
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
76
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wider", children: step.type }),
77
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: step.label })
78
+ ] })
79
+ ] });
80
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
81
+ index > 0 && onInsert && /* @__PURE__ */ jsx("div", { className: "relative pl-8 py-1", children: /* @__PURE__ */ jsx(
82
+ "button",
83
+ {
84
+ type: "button",
85
+ "data-slot": "step-timeline-insert",
86
+ onClick: () => onInsert(index),
87
+ className: "border border-dashed border-border/50 rounded-lg py-2 text-center text-xs text-muted-foreground/50 hover:text-muted-foreground hover:border-border cursor-pointer transition-colors w-full",
88
+ children: "+ Add Step"
89
+ }
90
+ ) }),
91
+ /* @__PURE__ */ jsxs("div", { "data-slot": "step-timeline-step", className: "relative pl-8 py-2", children: [
92
+ /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 w-3 h-3 rounded-full border-2 border-border bg-background z-10" }),
93
+ /* @__PURE__ */ jsxs("div", { "data-slot": "step-timeline-card", className: "border border-border rounded-lg overflow-hidden", children: [
94
+ isInteractive ? /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full px-4 py-3 gap-3", children: [
95
+ /* @__PURE__ */ jsx(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ "aria-expanded": expanded,
100
+ "aria-controls": bodyId,
101
+ onClick: () => onStepClick == null ? void 0 : onStepClick(step.id),
102
+ className: "flex items-center gap-3 flex-1 min-w-0 cursor-pointer hover:opacity-80 transition-opacity text-left",
103
+ children: headerContent
104
+ }
105
+ ),
106
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 shrink-0", children: [
107
+ renderStepAccessory && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: renderStepAccessory(step) }),
108
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 text-muted-foreground", children: expanded ? /* @__PURE__ */ jsx(ChevronUp, { size: 16 }) : /* @__PURE__ */ jsx(ChevronDown, { size: 16 }) })
109
+ ] })
110
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "w-full px-4 py-3 flex items-center gap-3", children: [
111
+ headerContent,
112
+ renderStepAccessory && /* @__PURE__ */ jsx("div", { className: "ml-auto shrink-0", children: renderStepAccessory(step) })
113
+ ] }),
114
+ expanded && renderStepBody && /* @__PURE__ */ jsx("div", { id: bodyId, "data-slot": "step-timeline-body", children: renderStepBody(step) })
115
+ ] })
116
+ ] })
117
+ ] }, step.id);
118
+ }),
119
+ onInsert && /* @__PURE__ */ jsx("div", { className: "relative pl-8 py-1", children: /* @__PURE__ */ jsx(
120
+ "button",
121
+ {
122
+ type: "button",
123
+ "data-slot": "step-timeline-insert",
124
+ onClick: () => onInsert(steps.length),
125
+ className: "border border-dashed border-border/50 rounded-lg py-2 text-center text-xs text-muted-foreground/50 hover:text-muted-foreground hover:border-border cursor-pointer transition-colors w-full",
126
+ children: "+ Add Step"
127
+ }
128
+ ) })
129
+ ] }));
130
+ }
131
+ export {
132
+ StepTimeline
133
+ };
134
+ //# sourceMappingURL=step-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/step-timeline.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { Mail, Phone, CheckSquare, Clock, Circle, ChevronUp, ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\n\ntype StepType = \"email\" | \"call\" | \"task\" | \"wait\" | (string & {})\n\ninterface TimelineStep {\n id: string\n type: StepType\n label: string\n}\n\ninterface StepTimelineProps extends React.HTMLAttributes<HTMLDivElement> {\n steps: TimelineStep[]\n expandedStepId?: string\n onStepClick?: (stepId: string) => void\n onInsert?: (index: number) => void\n renderStepBody?: (step: TimelineStep) => React.ReactNode\n renderStepAccessory?: (step: TimelineStep) => React.ReactNode\n}\n\nconst stepTypeConfig: Record<string, { icon: LucideIcon; classes: string }> = {\n email: { icon: Mail, classes: \"bg-blue-500/10 text-blue-600\" },\n call: { icon: Phone, classes: \"bg-emerald-500/10 text-emerald-600\" },\n task: { icon: CheckSquare, classes: \"bg-purple-500/10 text-purple-600\" },\n wait: { icon: Clock, classes: \"bg-muted text-muted-foreground\" },\n}\n\nconst defaultStepConfig: { icon: LucideIcon; classes: string } = { icon: Circle, classes: \"bg-muted text-muted-foreground\" }\n\nfunction StepTimeline({\n steps,\n expandedStepId,\n onStepClick,\n onInsert,\n renderStepBody,\n renderStepAccessory,\n className,\n ...rest\n}: StepTimelineProps) {\n return (\n <div data-slot=\"step-timeline\" className={cn(\"relative ml-5\", className)} {...rest}>\n <div className=\"absolute left-0 top-0 bottom-0 border-l-2 border-border\" />\n\n {steps.map((step, index) => {\n const expanded = step.id === expandedStepId\n const config = stepTypeConfig[step.type] ?? defaultStepConfig\n const TypeIcon = config.icon\n const isInteractive = !!(onStepClick || renderStepBody)\n const bodyId = `step-timeline-body-${step.id}`\n\n const headerContent = (\n <>\n <div className={cn(\"w-8 h-8 rounded-full flex items-center justify-center shrink-0\", config.classes)}>\n <TypeIcon size={16} />\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-[11px] font-medium text-muted-foreground uppercase tracking-wider\">\n {step.type}\n </span>\n <span className=\"text-sm font-medium\">{step.label}</span>\n </div>\n </>\n )\n\n return (\n <React.Fragment key={step.id}>\n {index > 0 && onInsert && (\n <div className=\"relative pl-8 py-1\">\n <button\n type=\"button\"\n data-slot=\"step-timeline-insert\"\n onClick={() => onInsert(index)}\n className=\"border border-dashed border-border/50 rounded-lg py-2 text-center text-xs text-muted-foreground/50 hover:text-muted-foreground hover:border-border cursor-pointer transition-colors w-full\"\n >\n + Add Step\n </button>\n </div>\n )}\n\n <div data-slot=\"step-timeline-step\" className=\"relative pl-8 py-2\">\n <div className=\"absolute left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 w-3 h-3 rounded-full border-2 border-border bg-background z-10\" />\n\n <div data-slot=\"step-timeline-card\" className=\"border border-border rounded-lg overflow-hidden\">\n {isInteractive ? (\n <div className=\"flex items-center w-full px-4 py-3 gap-3\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={bodyId}\n onClick={() => onStepClick?.(step.id)}\n className=\"flex items-center gap-3 flex-1 min-w-0 cursor-pointer hover:opacity-80 transition-opacity text-left\"\n >\n {headerContent}\n </button>\n <div className=\"ml-auto flex items-center gap-2 shrink-0\">\n {renderStepAccessory && (\n <div className=\"shrink-0\">\n {renderStepAccessory(step)}\n </div>\n )}\n <div className=\"shrink-0 text-muted-foreground\">\n {expanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />}\n </div>\n </div>\n </div>\n ) : (\n <div className=\"w-full px-4 py-3 flex items-center gap-3\">\n {headerContent}\n {renderStepAccessory && (\n <div className=\"ml-auto shrink-0\">\n {renderStepAccessory(step)}\n </div>\n )}\n </div>\n )}\n\n {expanded && renderStepBody && (\n <div id={bodyId} data-slot=\"step-timeline-body\">\n {renderStepBody(step)}\n </div>\n )}\n </div>\n </div>\n </React.Fragment>\n )\n })}\n\n {onInsert && (\n <div className=\"relative pl-8 py-1\">\n <button\n type=\"button\"\n data-slot=\"step-timeline-insert\"\n onClick={() => onInsert(steps.length)}\n className=\"border border-dashed border-border/50 rounded-lg py-2 text-center text-xs text-muted-foreground/50 hover:text-muted-foreground hover:border-border cursor-pointer transition-colors w-full\"\n >\n + Add Step\n </button>\n </div>\n )}\n </div>\n )\n}\n\nexport { StepTimeline, type StepTimelineProps, type TimelineStep, type StepType }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CM,SAUI,UAVJ,KAcM,YAdN;AA5CN,YAAY,WAAW;AAEvB,SAAS,MAAM,OAAO,aAAa,OAAO,QAAQ,WAAW,mBAAmB;AAEhF,SAAS,UAAU;AAmBnB,MAAM,iBAAwE;AAAA,EAC5E,OAAO,EAAE,MAAM,MAAM,SAAS,+BAA+B;AAAA,EAC7D,MAAM,EAAE,MAAM,OAAO,SAAS,qCAAqC;AAAA,EACnE,MAAM,EAAE,MAAM,aAAa,SAAS,mCAAmC;AAAA,EACvE,MAAM,EAAE,MAAM,OAAO,SAAS,iCAAiC;AACjE;AAEA,MAAM,oBAA2D,EAAE,MAAM,QAAQ,SAAS,iCAAiC;AAE3H,SAAS,aAAa,IASA;AATA,eACpB;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAzCF,IAkCsB,IAQjB,iBARiB,IAQjB;AAAA,IAPH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,SACE,qBAAC,sCAAI,aAAU,iBAAgB,WAAW,GAAG,iBAAiB,SAAS,KAAO,OAA7E,EACC;AAAA,wBAAC,SAAI,WAAU,2DAA0D;AAAA,IAExE,MAAM,IAAI,CAAC,MAAM,UAAU;AAhDlC,UAAAA;AAiDQ,YAAM,WAAW,KAAK,OAAO;AAC7B,YAAM,UAASA,MAAA,eAAe,KAAK,IAAI,MAAxB,OAAAA,MAA6B;AAC5C,YAAM,WAAW,OAAO;AACxB,YAAM,gBAAgB,CAAC,EAAE,eAAe;AACxC,YAAM,SAAS,sBAAsB,KAAK,EAAE;AAE5C,YAAM,gBACJ,iCACE;AAAA,4BAAC,SAAI,WAAW,GAAG,kEAAkE,OAAO,OAAO,GACjG,8BAAC,YAAS,MAAM,IAAI,GACtB;AAAA,QACA,qBAAC,SAAI,WAAU,yBACb;AAAA,8BAAC,UAAK,WAAU,0EACb,eAAK,MACR;AAAA,UACA,oBAAC,UAAK,WAAU,uBAAuB,eAAK,OAAM;AAAA,WACpD;AAAA,SACF;AAGF,aACE,qBAAC,MAAM,UAAN,EACE;AAAA,gBAAQ,KAAK,YACZ,oBAAC,SAAI,WAAU,sBACb;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,aAAU;AAAA,YACV,SAAS,MAAM,SAAS,KAAK;AAAA,YAC7B,WAAU;AAAA,YACX;AAAA;AAAA,QAED,GACF;AAAA,QAGF,qBAAC,SAAI,aAAU,sBAAqB,WAAU,sBAC5C;AAAA,8BAAC,SAAI,WAAU,4HAA2H;AAAA,UAE1I,qBAAC,SAAI,aAAU,sBAAqB,WAAU,mDAC3C;AAAA,4BACC,qBAAC,SAAI,WAAU,4CACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,iBAAe;AAAA,kBACf,iBAAe;AAAA,kBACf,SAAS,MAAM,2CAAc,KAAK;AAAA,kBAClC,WAAU;AAAA,kBAET;AAAA;AAAA,cACH;AAAA,cACA,qBAAC,SAAI,WAAU,4CACZ;AAAA,uCACC,oBAAC,SAAI,WAAU,YACZ,8BAAoB,IAAI,GAC3B;AAAA,gBAEF,oBAAC,SAAI,WAAU,kCACZ,qBAAW,oBAAC,aAAU,MAAM,IAAI,IAAK,oBAAC,eAAY,MAAM,IAAI,GAC/D;AAAA,iBACF;AAAA,eACF,IAEA,qBAAC,SAAI,WAAU,4CACZ;AAAA;AAAA,cACA,uBACC,oBAAC,SAAI,WAAU,oBACZ,8BAAoB,IAAI,GAC3B;AAAA,eAEJ;AAAA,YAGD,YAAY,kBACX,oBAAC,SAAI,IAAI,QAAQ,aAAU,sBACxB,yBAAe,IAAI,GACtB;AAAA,aAEJ;AAAA,WACF;AAAA,WAzDmB,KAAK,EA0D1B;AAAA,IAEJ,CAAC;AAAA,IAEA,YACC,oBAAC,SAAI,WAAU,sBACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,aAAU;AAAA,QACV,SAAS,MAAM,SAAS,MAAM,MAAM;AAAA,QACpC,WAAU;AAAA,QACX;AAAA;AAAA,IAED,GACF;AAAA,MAEJ;AAEJ;","names":["_a"]}
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+
3
+ interface StickyActionBarProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ left?: React.ReactNode;
5
+ right?: React.ReactNode;
6
+ bordered?: boolean;
7
+ }
8
+ declare function StickyActionBar({ left, right, bordered, className, ...rest }: StickyActionBarProps): React.JSX.Element;
9
+
10
+ export { StickyActionBar, type StickyActionBarProps };
@@ -0,0 +1,56 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+ import { jsx, jsxs } from "react/jsx-runtime";
33
+ import { cn } from "../lib/utils.js";
34
+ function StickyActionBar(_a) {
35
+ var _b = _a, { left, right, bordered = true, className } = _b, rest = __objRest(_b, ["left", "right", "bordered", "className"]);
36
+ return /* @__PURE__ */ jsxs(
37
+ "div",
38
+ __spreadProps(__spreadValues({
39
+ "data-slot": "sticky-action-bar",
40
+ className: cn(
41
+ "flex items-center justify-between sticky bottom-0 bg-background",
42
+ bordered && "pt-3 border-t border-border/50",
43
+ className
44
+ )
45
+ }, rest), {
46
+ children: [
47
+ left && /* @__PURE__ */ jsx("div", { "data-slot": "sticky-action-bar-left", className: "flex items-center gap-1", children: left }),
48
+ right && /* @__PURE__ */ jsx("div", { "data-slot": "sticky-action-bar-right", className: "ml-auto flex items-center gap-2", children: right })
49
+ ]
50
+ })
51
+ );
52
+ }
53
+ export {
54
+ StickyActionBar
55
+ };
56
+ //# sourceMappingURL=sticky-action-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/sticky-action-bar.tsx"],"sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\ninterface StickyActionBarProps extends React.HTMLAttributes<HTMLDivElement> {\n left?: React.ReactNode\n right?: React.ReactNode\n bordered?: boolean\n}\n\nfunction StickyActionBar({ left, right, bordered = true, className, ...rest }: StickyActionBarProps) {\n return (\n <div\n data-slot=\"sticky-action-bar\"\n className={cn(\n \"flex items-center justify-between sticky bottom-0 bg-background\",\n bordered && \"pt-3 border-t border-border/50\",\n className\n )}\n {...rest}\n >\n {left && (\n <div data-slot=\"sticky-action-bar-left\" className=\"flex items-center gap-1\">\n {left}\n </div>\n )}\n {right && (\n <div data-slot=\"sticky-action-bar-right\" className=\"ml-auto flex items-center gap-2\">\n {right}\n </div>\n )}\n </div>\n )\n}\n\nexport { StickyActionBar, type StickyActionBarProps }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYI,SAUI,KAVJ;AAVJ,SAAS,UAAU;AAQnB,SAAS,gBAAgB,IAA4E;AAA5E,eAAE,QAAM,OAAO,WAAW,MAAM,UAVzD,IAUyB,IAA8C,iBAA9C,IAA8C,CAA5C,QAAM,SAAO,YAAiB;AACvD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,MACF;AAAA,OACI,OAPL;AAAA,MASE;AAAA,gBACC,oBAAC,SAAI,aAAU,0BAAyB,WAAU,2BAC/C,gBACH;AAAA,QAED,SACC,oBAAC,SAAI,aAAU,2BAA0B,WAAU,mCAChD,iBACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
@@ -39,7 +39,6 @@ import {
39
39
  ThumbsUp,
40
40
  ThumbsDown,
41
41
  Check,
42
- RefreshCw,
43
42
  ArrowLeft,
44
43
  Mail,
45
44
  Phone,
@@ -52,17 +51,8 @@ import {
52
51
  Globe
53
52
  } from "lucide-react";
54
53
  import { Button } from "./button.js";
55
- function BrandIcon({ src, alt, className }) {
56
- return /* @__PURE__ */ jsx(
57
- "img",
58
- {
59
- src,
60
- alt,
61
- className: `${className != null ? className : ""} object-contain`,
62
- draggable: false
63
- }
64
- );
65
- }
54
+ import { DraftFeedbackInline } from "./draft-feedback-inline.js";
55
+ import { AccountContactsPopover, BrandIcon } from "./account-contacts-popover.js";
66
56
  function getActionTypeIcon(type, className, iconMap) {
67
57
  switch (type) {
68
58
  case "email":
@@ -138,143 +128,6 @@ function AiEditPanel({ onApply }) {
138
128
  ] })
139
129
  ] });
140
130
  }
141
- const positivePills = ["Tone", "Personalization", "Length", "CTA", "Other"];
142
- const negativePills = ["Too formal", "Too casual", "Too long", "Missing context", "Wrong angle", "Factual error", "Other"];
143
- function DraftFeedbackInline({
144
- onRegenerateRequest,
145
- onSubmitFeedback,
146
- onDiscardRequest
147
- }) {
148
- const [thumbState, setThumbState] = React.useState(null);
149
- const [selectedPills, setSelectedPills] = React.useState([]);
150
- const [detailText, setDetailText] = React.useState("");
151
- const [noted, setNoted] = React.useState(false);
152
- const [regenerated, setRegenerated] = React.useState(false);
153
- const togglePill = React.useCallback((pill) => {
154
- setSelectedPills((prev) => prev.includes(pill) ? prev.filter((p) => p !== pill) : [...prev, pill]);
155
- }, []);
156
- const handleSubmit = React.useCallback(() => {
157
- if (!thumbState) return;
158
- onSubmitFeedback == null ? void 0 : onSubmitFeedback(thumbState, selectedPills, detailText);
159
- setNoted(true);
160
- setTimeout(() => {
161
- setThumbState(null);
162
- setSelectedPills([]);
163
- setDetailText("");
164
- setNoted(false);
165
- }, 3e3);
166
- }, [thumbState, selectedPills, detailText, onSubmitFeedback]);
167
- const handleRegenerate = React.useCallback(() => {
168
- if (!thumbState) return;
169
- onRegenerateRequest == null ? void 0 : onRegenerateRequest(selectedPills, detailText);
170
- setRegenerated(true);
171
- setTimeout(() => {
172
- setThumbState(null);
173
- setSelectedPills([]);
174
- setDetailText("");
175
- setRegenerated(false);
176
- }, 3e3);
177
- }, [thumbState, selectedPills, detailText, onRegenerateRequest]);
178
- const handleDiscard = React.useCallback(() => {
179
- if (!thumbState) return;
180
- onDiscardRequest == null ? void 0 : onDiscardRequest(selectedPills, detailText);
181
- }, [thumbState, selectedPills, detailText, onDiscardRequest]);
182
- if (noted) {
183
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 py-1 animate-in fade-in slide-in-from-top-1 duration-200", children: [
184
- /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 text-emerald-500" }),
185
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Feedback recorded" })
186
- ] });
187
- }
188
- if (regenerated) {
189
- return /* @__PURE__ */ jsx("div", { className: "py-2 animate-in fade-in slide-in-from-top-1 duration-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 rounded-md bg-indigo-50 dark:bg-indigo-950/30 border border-indigo-200 dark:border-indigo-800", children: [
190
- /* @__PURE__ */ jsx(RefreshCw, { className: "w-3 h-3 text-indigo-500 animate-spin" }),
191
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-indigo-600 dark:text-indigo-400", children: "Regenerating draft..." })
192
- ] }) });
193
- }
194
- return /* @__PURE__ */ jsxs("div", { className: "space-y-0", children: [
195
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
196
- /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground font-medium", children: "How's this draft?" }),
197
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
198
- /* @__PURE__ */ jsx(
199
- "button",
200
- {
201
- onClick: () => {
202
- setThumbState(thumbState === "up" ? null : "up");
203
- setSelectedPills([]);
204
- setDetailText("");
205
- },
206
- className: `p-1.5 rounded transition-colors ${thumbState === "up" ? "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400" : "hover:bg-muted text-muted-foreground hover:text-foreground"}`,
207
- children: /* @__PURE__ */ jsx(ThumbsUp, { className: "w-4 h-4", fill: thumbState === "up" ? "currentColor" : "none" })
208
- }
209
- ),
210
- /* @__PURE__ */ jsx(
211
- "button",
212
- {
213
- onClick: () => {
214
- setThumbState(thumbState === "down" ? null : "down");
215
- setSelectedPills([]);
216
- setDetailText("");
217
- },
218
- className: `p-1.5 rounded transition-colors ${thumbState === "down" ? "bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400" : "hover:bg-muted text-muted-foreground hover:text-foreground"}`,
219
- children: /* @__PURE__ */ jsx(ThumbsDown, { className: "w-4 h-4", fill: thumbState === "down" ? "currentColor" : "none" })
220
- }
221
- )
222
- ] })
223
- ] }),
224
- thumbState && /* @__PURE__ */ jsxs("div", { className: "pt-3 space-y-3 animate-in fade-in slide-in-from-top-2 duration-200", children: [
225
- /* @__PURE__ */ jsxs("div", { children: [
226
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mb-2 block font-medium", children: thumbState === "up" ? "What worked well?" : "What needs improvement?" }),
227
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: (thumbState === "up" ? positivePills : negativePills).map((pill) => /* @__PURE__ */ jsx(
228
- "button",
229
- {
230
- onClick: () => togglePill(pill),
231
- className: `px-2.5 py-1 rounded-full text-[11px] font-medium border transition-colors ${selectedPills.includes(pill) ? thumbState === "up" ? "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800" : "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800" : "bg-background text-muted-foreground border-border hover:bg-muted/50 hover:text-foreground"}`,
232
- children: pill
233
- },
234
- pill
235
- )) })
236
- ] }),
237
- /* @__PURE__ */ jsx(
238
- "textarea",
239
- {
240
- value: detailText,
241
- onChange: (e) => setDetailText(e.target.value),
242
- placeholder: thumbState === "up" ? "Add specific praise (optional)..." : "Provide specific instructions (optional)...",
243
- className: "w-full text-xs bg-background border border-border rounded-md px-2.5 py-2 text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-indigo-500/50 focus:border-indigo-500/50 resize-none min-h-[60px]"
244
- }
245
- ),
246
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 pt-1", children: thumbState === "down" ? /* @__PURE__ */ jsxs(Fragment, { children: [
247
- /* @__PURE__ */ jsxs(
248
- "button",
249
- {
250
- onClick: handleRegenerate,
251
- disabled: selectedPills.length === 0 && detailText.length === 0,
252
- className: `flex-1 py-1.5 rounded-md text-xs font-semibold transition-colors flex items-center justify-center gap-1.5 ${selectedPills.length > 0 || detailText.length > 0 ? "bg-foreground text-background hover:bg-foreground/90" : "bg-muted text-muted-foreground cursor-not-allowed"}`,
253
- children: [
254
- /* @__PURE__ */ jsx(RefreshCw, { className: "w-3 h-3" }),
255
- "Regenerate draft"
256
- ]
257
- }
258
- ),
259
- /* @__PURE__ */ jsx(
260
- "button",
261
- {
262
- onClick: handleDiscard,
263
- className: "flex-1 py-1.5 rounded-md text-xs font-medium transition-colors border bg-background text-foreground border-border hover:bg-muted/50 flex items-center justify-center gap-1.5",
264
- children: "Discard draft"
265
- }
266
- )
267
- ] }) : /* @__PURE__ */ jsx(
268
- "button",
269
- {
270
- onClick: handleSubmit,
271
- className: "flex-1 py-1.5 rounded-md text-xs font-semibold transition-colors bg-foreground text-background hover:bg-foreground/90 border-transparent",
272
- children: "Submit feedback"
273
- }
274
- ) })
275
- ] })
276
- ] });
277
- }
278
131
  function EditorToolbar() {
279
132
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-4 py-2 border-t border-border bg-muted/5 flex-wrap", children: [
280
133
  /* @__PURE__ */ jsxs("div", { className: "flex items-center mr-2 gap-1 shrink-0", children: [
@@ -473,161 +326,6 @@ function ContactCard({
473
326
  }
474
327
  );
475
328
  }
476
- function AccountContactsPopover({
477
- contacts,
478
- onSelect,
479
- onSelectTo,
480
- onSelectCc,
481
- onSelectBcc,
482
- onViewAll,
483
- onOpenRecentActivity,
484
- trigger,
485
- iconMap
486
- }) {
487
- const [open, setOpen] = React.useState(false);
488
- const triggerRef = React.useRef(null);
489
- const [popoverStyle, setPopoverStyle] = React.useState({});
490
- React.useEffect(() => {
491
- if (open && triggerRef.current) {
492
- const rect = triggerRef.current.getBoundingClientRect();
493
- const popoverWidth = Math.min(448, window.innerWidth - 32);
494
- let left = rect.right - popoverWidth;
495
- if (left < 16) left = 16;
496
- if (left + popoverWidth > window.innerWidth - 16) left = window.innerWidth - 16 - popoverWidth;
497
- setPopoverStyle({ position: "fixed", top: rect.bottom + 4, left });
498
- }
499
- }, [open]);
500
- return /* @__PURE__ */ jsxs("div", { children: [
501
- /* @__PURE__ */ jsx("div", { ref: triggerRef, onClick: () => setOpen(!open), children: trigger }),
502
- open && /* @__PURE__ */ jsxs(Fragment, { children: [
503
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setOpen(false) }),
504
- /* @__PURE__ */ jsxs("div", { style: popoverStyle, className: "fixed bg-background border border-border rounded-lg shadow-xl z-50 w-[28rem] max-w-[calc(100vw-2rem)] py-2 animate-in fade-in slide-in-from-top-1 duration-150", children: [
505
- /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 text-[11px] font-medium text-muted-foreground/60 uppercase tracking-wide", children: "Account Contacts" }),
506
- /* @__PURE__ */ jsx("div", { className: "max-h-48 overflow-y-auto", children: contacts.map((c, i) => {
507
- var _a, _b, _c, _d, _e, _f;
508
- return /* @__PURE__ */ jsxs(
509
- "div",
510
- {
511
- role: "button",
512
- onClick: () => {
513
- (onSelectTo != null ? onSelectTo : onSelect)(c);
514
- setOpen(false);
515
- },
516
- className: "flex items-center gap-3 w-full px-3 py-2 text-left hover:bg-muted/50 transition-colors cursor-pointer",
517
- children: [
518
- /* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-full bg-muted flex items-center justify-center text-[10px] font-medium text-muted-foreground shrink-0", children: c.name.split(" ").map((n) => n[0]).join("") }),
519
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 overflow-hidden", children: [
520
- /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium text-foreground", children: c.name }),
521
- /* @__PURE__ */ jsxs("div", { className: "truncate text-xs text-muted-foreground leading-tight", children: [
522
- c.role,
523
- " \xB7 ",
524
- (_f = (_e = (_c = (_b = c.email) != null ? _b : (_a = c.emails) == null ? void 0 : _a[0]) != null ? _c : c.phone) != null ? _e : (_d = c.phones) == null ? void 0 : _d[0]) != null ? _f : ""
525
- ] }),
526
- c.lastActivity && /* @__PURE__ */ jsxs(
527
- "button",
528
- {
529
- type: "button",
530
- onClick: (e) => {
531
- e.stopPropagation();
532
- onOpenRecentActivity == null ? void 0 : onOpenRecentActivity();
533
- setOpen(false);
534
- },
535
- className: "mt-1.5 flex max-w-full items-center gap-1.5 overflow-hidden rounded-md border border-border/70 bg-muted/30 px-2 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
536
- children: [
537
- /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3 shrink-0" }),
538
- /* @__PURE__ */ jsx("span", { className: "shrink-0 font-medium", children: "Last activity" }),
539
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground/60", children: "\xB7" }),
540
- /* @__PURE__ */ jsx("span", { className: "shrink-0", children: c.lastActivity.date }),
541
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground/60", children: "\xB7" }),
542
- /* @__PURE__ */ jsx("span", { className: "truncate capitalize", children: c.lastActivity.type })
543
- ]
544
- }
545
- )
546
- ] }),
547
- /* @__PURE__ */ jsxs("div", { className: "ml-2 flex items-center gap-1.5 shrink-0", children: [
548
- onSelectTo && /* @__PURE__ */ jsx(
549
- "button",
550
- {
551
- type: "button",
552
- onClick: (e) => {
553
- e.stopPropagation();
554
- onSelectTo(c);
555
- setOpen(false);
556
- },
557
- className: "h-6 rounded border border-border bg-background px-1.5 text-[10px] text-muted-foreground hover:text-foreground hover:bg-muted/40",
558
- children: "To"
559
- }
560
- ),
561
- onSelectCc && /* @__PURE__ */ jsx(
562
- "button",
563
- {
564
- type: "button",
565
- onClick: (e) => {
566
- e.stopPropagation();
567
- onSelectCc(c);
568
- setOpen(false);
569
- },
570
- className: "h-6 rounded border border-border bg-background px-1.5 text-[10px] text-muted-foreground hover:text-foreground hover:bg-muted/40",
571
- children: "Cc"
572
- }
573
- ),
574
- onSelectBcc && /* @__PURE__ */ jsx(
575
- "button",
576
- {
577
- type: "button",
578
- onClick: (e) => {
579
- e.stopPropagation();
580
- onSelectBcc(c);
581
- setOpen(false);
582
- },
583
- className: "h-6 rounded border border-border bg-background px-1.5 text-[10px] text-muted-foreground hover:text-foreground hover:bg-muted/40",
584
- children: "Bcc"
585
- }
586
- ),
587
- /* @__PURE__ */ jsx(
588
- "button",
589
- {
590
- type: "button",
591
- onClick: (e) => {
592
- e.stopPropagation();
593
- if (c.salesforceUrl) {
594
- window.open(c.salesforceUrl, "_blank", "noopener,noreferrer");
595
- } else {
596
- onViewAll == null ? void 0 : onViewAll();
597
- }
598
- },
599
- className: "h-7 w-7 inline-flex items-center justify-center rounded-md border border-border bg-background hover:bg-muted/40 transition-colors shrink-0",
600
- "aria-label": `Open ${c.name} in Salesforce`,
601
- children: (iconMap == null ? void 0 : iconMap.salesforce) ? /* @__PURE__ */ jsx(BrandIcon, { src: iconMap.salesforce, alt: "Salesforce", className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsx(ExternalLink, { className: "w-3.5 h-3.5 text-muted-foreground" })
602
- }
603
- )
604
- ] })
605
- ]
606
- },
607
- i
608
- );
609
- }) }),
610
- onViewAll && /* @__PURE__ */ jsxs(Fragment, { children: [
611
- /* @__PURE__ */ jsx("div", { className: "h-px bg-border mx-3 my-1" }),
612
- /* @__PURE__ */ jsxs(
613
- "button",
614
- {
615
- onClick: () => {
616
- onViewAll();
617
- setOpen(false);
618
- },
619
- className: "flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
620
- children: [
621
- /* @__PURE__ */ jsx(ExternalLink, { className: "w-3 h-3" }),
622
- "View all contacts"
623
- ]
624
- }
625
- )
626
- ] })
627
- ] })
628
- ] })
629
- ] });
630
- }
631
329
  function EmailHeader({
632
330
  fromName,
633
331
  fromEmail,