@wealthx/shadcn 1.5.16 → 1.5.18
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/.turbo/turbo-build.log +130 -130
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-UJMVXREM.mjs → chunk-2UA4CPE5.mjs} +1 -1
- package/dist/{chunk-DYSVJ473.mjs → chunk-2VTOF7PW.mjs} +1 -1
- package/dist/{chunk-6MDNL5I2.mjs → chunk-45V7X563.mjs} +3 -3
- package/dist/{chunk-RKHKBEE6.mjs → chunk-5BU7TNB4.mjs} +2 -2
- package/dist/{chunk-B7DD3ODQ.mjs → chunk-7T4TYUO3.mjs} +2 -2
- package/dist/{chunk-JGBV3XMQ.mjs → chunk-ANERULZS.mjs} +2 -2
- package/dist/{chunk-LRQSY3TP.mjs → chunk-C4ESZLGT.mjs} +142 -69
- package/dist/{chunk-5YVJSKFH.mjs → chunk-DKH35J4U.mjs} +2 -2
- package/dist/{chunk-MXP2RX2V.mjs → chunk-ET4MTPIY.mjs} +1 -1
- package/dist/{chunk-QHAMVWDG.mjs → chunk-G7YCLJ53.mjs} +2 -2
- package/dist/{chunk-XAS6KBIG.mjs → chunk-JJSA772M.mjs} +1 -1
- package/dist/{chunk-MNMSHB2J.mjs → chunk-K3XP5ETH.mjs} +2 -2
- package/dist/{chunk-I4P7RXAE.mjs → chunk-KJQ3BVTB.mjs} +1 -1
- package/dist/{chunk-MUV4EGDW.mjs → chunk-KPGARKFC.mjs} +1 -1
- package/dist/{chunk-R6U246E4.mjs → chunk-L7IZ3YHI.mjs} +1 -1
- package/dist/{chunk-P7CEBZM6.mjs → chunk-LSRGA5BI.mjs} +19 -5
- package/dist/{chunk-GMF7INNS.mjs → chunk-LWYMZHN7.mjs} +2 -2
- package/dist/{chunk-XMP24PWA.mjs → chunk-NXZ2F4JA.mjs} +1 -1
- package/dist/{chunk-4X4MGYHE.mjs → chunk-PUGQVHQL.mjs} +1 -1
- package/dist/{chunk-LPVXO3TD.mjs → chunk-RFWP2325.mjs} +2 -2
- package/dist/{chunk-3KLJ4XRE.mjs → chunk-RPOIXMHW.mjs} +1 -1
- package/dist/{chunk-IFSQWDRN.mjs → chunk-SH5L5VG6.mjs} +1 -1
- package/dist/{chunk-FW4U543X.mjs → chunk-STDCXTUU.mjs} +2 -2
- package/dist/{chunk-2KNQZG5S.mjs → chunk-SU6TPDEU.mjs} +1 -1
- package/dist/{chunk-K4WDPVFY.mjs → chunk-WZFBLRNP.mjs} +1 -1
- package/dist/{chunk-UYRHYJPX.mjs → chunk-XNX3XJ2F.mjs} +1 -1
- package/dist/components/ui/about-you-form.js +17 -4
- package/dist/components/ui/about-you-form.mjs +3 -3
- package/dist/components/ui/add-column-modal.js +17 -4
- package/dist/components/ui/add-column-modal.mjs +2 -2
- package/dist/components/ui/ai-conversations.js +458 -345
- package/dist/components/ui/ai-conversations.mjs +2 -1
- package/dist/components/ui/appointment-action-dialogs.js +17 -4
- package/dist/components/ui/appointment-action-dialogs.mjs +2 -2
- package/dist/components/ui/appointment-availability-settings.js +17 -4
- package/dist/components/ui/appointment-availability-settings.mjs +4 -4
- package/dist/components/ui/appointment-book-dialog.js +17 -4
- package/dist/components/ui/appointment-book-dialog.mjs +3 -3
- package/dist/components/ui/appointment-detail-sheet.js +17 -4
- package/dist/components/ui/appointment-detail-sheet.mjs +3 -3
- package/dist/components/ui/appointment-upcoming-card.js +17 -4
- package/dist/components/ui/appointment-upcoming-card.mjs +2 -2
- package/dist/components/ui/backoffice-signup-steps.js +17 -4
- package/dist/components/ui/backoffice-signup-steps.mjs +4 -4
- package/dist/components/ui/bank-statement-generate-dialog.js +17 -4
- package/dist/components/ui/bank-statement-generate-dialog.mjs +5 -5
- package/dist/components/ui/chat-widget.js +17 -4
- package/dist/components/ui/chat-widget.mjs +3 -3
- package/dist/components/ui/contact-alert-dialog/index.js +17 -4
- package/dist/components/ui/contact-alert-dialog/index.mjs +3 -3
- package/dist/components/ui/create-contact-modal.js +17 -4
- package/dist/components/ui/create-contact-modal.mjs +3 -3
- package/dist/components/ui/date-picker.mjs +2 -2
- package/dist/components/ui/expense-detail-item.mjs +3 -3
- package/dist/components/ui/expense-work-details.mjs +3 -3
- package/dist/components/ui/field.js +17 -4
- package/dist/components/ui/field.mjs +2 -2
- package/dist/components/ui/form-primitives.js +17 -4
- package/dist/components/ui/form-primitives.mjs +2 -2
- package/dist/components/ui/frontend-signup-steps.js +17 -4
- package/dist/components/ui/frontend-signup-steps.mjs +6 -6
- package/dist/components/ui/income-work-details.mjs +3 -3
- package/dist/components/ui/label.js +20 -4
- package/dist/components/ui/label.mjs +1 -1
- package/dist/components/ui/opportunity-edit-modals.js +17 -4
- package/dist/components/ui/opportunity-edit-modals.mjs +5 -5
- package/dist/components/ui/opportunity-summary-tab.js +17 -4
- package/dist/components/ui/opportunity-summary-tab.mjs +6 -6
- package/dist/components/ui/pipeline-dialogs.mjs +3 -3
- package/dist/components/ui/property-report-dialog.js +17 -4
- package/dist/components/ui/property-report-dialog.mjs +4 -4
- package/dist/components/ui/review-alerts-dialog.js +17 -4
- package/dist/components/ui/review-alerts-dialog.mjs +2 -2
- package/dist/components/ui/savings-goal-modal.mjs +2 -2
- package/dist/components/ui/share-details-dialog.js +17 -4
- package/dist/components/ui/share-details-dialog.mjs +2 -2
- package/dist/components/ui/signup-form-primitives.js +17 -4
- package/dist/components/ui/signup-form-primitives.mjs +3 -3
- package/dist/components/ui/two-fa-setup-form.js +17 -4
- package/dist/components/ui/two-fa-setup-form.mjs +3 -3
- package/dist/index.js +1360 -1281
- package/dist/index.mjs +35 -35
- package/dist/styles.css +1 -1
- package/package.json +9 -1
- package/src/components/ui/ai-conversations.tsx +161 -83
- package/src/components/ui/label.tsx +18 -3
- package/src/styles/styles-css.ts +1 -1
- package/dist/{chunk-TRM3KIHT.mjs → chunk-UMF6LLQK.mjs} +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wealthx/shadcn",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.18",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"@fontsource-variable/figtree": "^5.2.10",
|
|
19
19
|
"@react-awesome-query-builder/ui": "6.7.0-alpha.0",
|
|
20
20
|
"@tanstack/react-table": "8.21.3",
|
|
21
|
+
"@tiptap/extension-link": "^3.23.6",
|
|
22
|
+
"@tiptap/extension-underline": "^3.23.6",
|
|
23
|
+
"@tiptap/pm": "^3.23.6",
|
|
24
|
+
"@tiptap/react": "^3.23.6",
|
|
25
|
+
"@tiptap/starter-kit": "^3.23.6",
|
|
21
26
|
"chart.js": "^4.5.1",
|
|
22
27
|
"chartjs-plugin-datalabels": "^2.2.0",
|
|
23
28
|
"class-variance-authority": "^0.7.1",
|
|
@@ -27,6 +32,9 @@
|
|
|
27
32
|
"lucide-react": "^0.577.0",
|
|
28
33
|
"react-chartjs-2": "^5.3.1",
|
|
29
34
|
"react-day-picker": "^9.14.0",
|
|
35
|
+
"react-markdown": "^10.1.0",
|
|
36
|
+
"rehype-raw": "^7.0.0",
|
|
37
|
+
"rehype-sanitize": "^6.0.0",
|
|
30
38
|
"sonner": "^2.0.7",
|
|
31
39
|
"tailwind-merge": "^3.5.0",
|
|
32
40
|
"tw-animate-css": "^1.4.0",
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
|
+
import { useEditor, EditorContent } from "@tiptap/react";
|
|
3
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
4
|
+
import TiptapUnderline from "@tiptap/extension-underline";
|
|
5
|
+
import TiptapLink from "@tiptap/extension-link";
|
|
6
|
+
import ReactMarkdown from "react-markdown";
|
|
7
|
+
import rehypeRaw from "rehype-raw";
|
|
8
|
+
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
|
|
2
9
|
import {
|
|
3
10
|
Archive,
|
|
4
11
|
ArrowLeft,
|
|
@@ -51,6 +58,7 @@ import {
|
|
|
51
58
|
DialogHeader,
|
|
52
59
|
DialogTitle,
|
|
53
60
|
} from "@/components/ui/dialog";
|
|
61
|
+
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
54
62
|
import { Separator } from "@/components/ui/separator";
|
|
55
63
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
56
64
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
@@ -639,13 +647,15 @@ export function ChatBubble({ message, className }: ChatBubbleProps) {
|
|
|
639
647
|
{/* Bubble */}
|
|
640
648
|
<div
|
|
641
649
|
className={cn(
|
|
642
|
-
"px-3 py-2 text-sm leading-relaxed",
|
|
643
|
-
isBot && "border border-border bg-muted/60 text-foreground",
|
|
644
|
-
isVisitor && "border border-border bg-background text-foreground",
|
|
645
|
-
isAdvisor && "bg-primary text-primary-foreground",
|
|
650
|
+
"px-3 py-2 text-sm leading-relaxed break-words [&_a]:underline [&_p]:m-0",
|
|
651
|
+
isBot && "border border-border bg-muted/60 text-foreground [&_a]:text-primary",
|
|
652
|
+
isVisitor && "border border-border bg-background text-foreground [&_a]:text-primary",
|
|
653
|
+
isAdvisor && "bg-primary text-primary-foreground [&_a]:text-primary-foreground",
|
|
646
654
|
)}
|
|
647
655
|
>
|
|
648
|
-
{
|
|
656
|
+
<ReactMarkdown rehypePlugins={[rehypeRaw, [rehypeSanitize, defaultSchema]]}>
|
|
657
|
+
{content}
|
|
658
|
+
</ReactMarkdown>
|
|
649
659
|
</div>
|
|
650
660
|
|
|
651
661
|
{timestamp && (
|
|
@@ -692,6 +702,107 @@ export interface ChatComposerProps {
|
|
|
692
702
|
className?: string;
|
|
693
703
|
}
|
|
694
704
|
|
|
705
|
+
function ComposerToolbarButton({
|
|
706
|
+
label,
|
|
707
|
+
icon: Icon,
|
|
708
|
+
pressed,
|
|
709
|
+
onToggle,
|
|
710
|
+
}: {
|
|
711
|
+
label: string;
|
|
712
|
+
icon: React.ElementType;
|
|
713
|
+
pressed?: boolean;
|
|
714
|
+
onToggle?: () => void;
|
|
715
|
+
}) {
|
|
716
|
+
return (
|
|
717
|
+
<button
|
|
718
|
+
type="button"
|
|
719
|
+
aria-label={label}
|
|
720
|
+
aria-pressed={pressed}
|
|
721
|
+
onClick={onToggle}
|
|
722
|
+
className={cn(
|
|
723
|
+
"flex size-7 items-center justify-center transition-colors",
|
|
724
|
+
pressed
|
|
725
|
+
? "bg-foreground text-background"
|
|
726
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
727
|
+
)}
|
|
728
|
+
>
|
|
729
|
+
<Icon className="size-3.5" />
|
|
730
|
+
</button>
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function ComposerLinkPopover({ editor }: { editor: ReturnType<typeof useEditor> }) {
|
|
735
|
+
const [open, setOpen] = React.useState(false);
|
|
736
|
+
const [url, setUrl] = React.useState("");
|
|
737
|
+
|
|
738
|
+
const handleApply = () => {
|
|
739
|
+
if (url.trim()) {
|
|
740
|
+
editor?.chain().focus().setLink({ href: url.trim() }).run();
|
|
741
|
+
}
|
|
742
|
+
setOpen(false);
|
|
743
|
+
setUrl("");
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
return (
|
|
747
|
+
<Popover
|
|
748
|
+
open={open}
|
|
749
|
+
onOpenChange={(newOpen) => {
|
|
750
|
+
if (newOpen && editor?.isActive("link")) {
|
|
751
|
+
editor.chain().focus().unsetLink().run();
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (newOpen) setUrl("");
|
|
755
|
+
setOpen(newOpen);
|
|
756
|
+
}}
|
|
757
|
+
>
|
|
758
|
+
<PopoverTrigger
|
|
759
|
+
aria-label="Insert link"
|
|
760
|
+
className={cn(
|
|
761
|
+
"flex size-7 items-center justify-center transition-colors",
|
|
762
|
+
editor?.isActive("link")
|
|
763
|
+
? "bg-foreground text-background"
|
|
764
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
765
|
+
)}
|
|
766
|
+
>
|
|
767
|
+
<Link2 className="size-3.5" />
|
|
768
|
+
</PopoverTrigger>
|
|
769
|
+
<PopoverContent className="w-72 p-2" align="start">
|
|
770
|
+
<div className="flex items-center gap-1.5">
|
|
771
|
+
<input
|
|
772
|
+
type="url"
|
|
773
|
+
value={url}
|
|
774
|
+
onChange={(e) => setUrl(e.target.value)}
|
|
775
|
+
onKeyDown={(e) => e.key === "Enter" && handleApply()}
|
|
776
|
+
placeholder="https://"
|
|
777
|
+
className="min-w-0 flex-1 border border-border bg-transparent px-2 py-1.5 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:border-primary"
|
|
778
|
+
autoFocus
|
|
779
|
+
/>
|
|
780
|
+
<Button size="sm" className="h-8 px-3" onClick={handleApply}>
|
|
781
|
+
Apply
|
|
782
|
+
</Button>
|
|
783
|
+
</div>
|
|
784
|
+
</PopoverContent>
|
|
785
|
+
</Popover>
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function ComposerEmailFieldRow({
|
|
790
|
+
label,
|
|
791
|
+
children,
|
|
792
|
+
}: {
|
|
793
|
+
label: string;
|
|
794
|
+
children: React.ReactNode;
|
|
795
|
+
}) {
|
|
796
|
+
return (
|
|
797
|
+
<div className="flex items-center gap-3 border-b border-border px-4 py-2.5">
|
|
798
|
+
<span className="w-14 shrink-0 text-sm text-muted-foreground">
|
|
799
|
+
{label}
|
|
800
|
+
</span>
|
|
801
|
+
{children}
|
|
802
|
+
</div>
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
|
|
695
806
|
export function ChatComposer({
|
|
696
807
|
mode,
|
|
697
808
|
channel: channelProp = "chat",
|
|
@@ -715,61 +826,30 @@ export function ChatComposer({
|
|
|
715
826
|
const [emailCc, setEmailCc] = React.useState("");
|
|
716
827
|
const [showCc, setShowCc] = React.useState(false);
|
|
717
828
|
const [emailSubject, setEmailSubject] = React.useState("");
|
|
718
|
-
|
|
719
|
-
const [
|
|
720
|
-
|
|
829
|
+
|
|
830
|
+
const [, forceUpdate] = React.useReducer((x: number) => x + 1, 0);
|
|
831
|
+
|
|
832
|
+
const editor = useEditor({
|
|
833
|
+
extensions: [
|
|
834
|
+
StarterKit,
|
|
835
|
+
TiptapUnderline,
|
|
836
|
+
TiptapLink.configure({ openOnClick: false }),
|
|
837
|
+
],
|
|
838
|
+
content: "",
|
|
839
|
+
onTransaction: () => forceUpdate(),
|
|
840
|
+
editorProps: {
|
|
841
|
+
attributes: {
|
|
842
|
+
class:
|
|
843
|
+
"min-h-[150px] px-4 py-3 text-base text-foreground outline-none prose prose-sm max-w-none [&_p]:m-0 [&_a]:text-primary [&_a]:underline [&_a]:cursor-pointer",
|
|
844
|
+
},
|
|
845
|
+
},
|
|
846
|
+
});
|
|
721
847
|
|
|
722
848
|
const handleChannelChange = (c: AiConvChannel) => {
|
|
723
849
|
setChannel(c);
|
|
724
850
|
onChannelChange?.(c);
|
|
725
851
|
};
|
|
726
852
|
|
|
727
|
-
function ToolbarButton({
|
|
728
|
-
label,
|
|
729
|
-
icon: Icon,
|
|
730
|
-
pressed,
|
|
731
|
-
onToggle,
|
|
732
|
-
}: {
|
|
733
|
-
label: string;
|
|
734
|
-
icon: React.ElementType;
|
|
735
|
-
pressed?: boolean;
|
|
736
|
-
onToggle?: () => void;
|
|
737
|
-
}) {
|
|
738
|
-
return (
|
|
739
|
-
<button
|
|
740
|
-
type="button"
|
|
741
|
-
aria-label={label}
|
|
742
|
-
aria-pressed={pressed}
|
|
743
|
-
onClick={onToggle}
|
|
744
|
-
className={cn(
|
|
745
|
-
"flex size-7 items-center justify-center transition-colors",
|
|
746
|
-
pressed
|
|
747
|
-
? "bg-foreground text-background"
|
|
748
|
-
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
749
|
-
)}
|
|
750
|
-
>
|
|
751
|
-
<Icon className="size-3.5" />
|
|
752
|
-
</button>
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
function EmailFieldRow({
|
|
757
|
-
label,
|
|
758
|
-
children,
|
|
759
|
-
}: {
|
|
760
|
-
label: string;
|
|
761
|
-
children: React.ReactNode;
|
|
762
|
-
}) {
|
|
763
|
-
return (
|
|
764
|
-
<div className="flex items-center gap-3 border-b border-border px-4 py-2.5">
|
|
765
|
-
<span className="w-14 shrink-0 text-sm text-muted-foreground">
|
|
766
|
-
{label}
|
|
767
|
-
</span>
|
|
768
|
-
{children}
|
|
769
|
-
</div>
|
|
770
|
-
);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
853
|
return (
|
|
774
854
|
<div
|
|
775
855
|
className={cn(
|
|
@@ -822,7 +902,7 @@ export function ChatComposer({
|
|
|
822
902
|
)}
|
|
823
903
|
aria-hidden={channel !== "email"}
|
|
824
904
|
>
|
|
825
|
-
<
|
|
905
|
+
<ComposerEmailFieldRow label="To">
|
|
826
906
|
<input
|
|
827
907
|
type="email"
|
|
828
908
|
value={emailTo}
|
|
@@ -838,9 +918,9 @@ export function ChatComposer({
|
|
|
838
918
|
CC
|
|
839
919
|
<ChevronDown className="size-3.5" />
|
|
840
920
|
</button>
|
|
841
|
-
</
|
|
921
|
+
</ComposerEmailFieldRow>
|
|
842
922
|
{showCc && (
|
|
843
|
-
<
|
|
923
|
+
<ComposerEmailFieldRow label="CC">
|
|
844
924
|
<input
|
|
845
925
|
type="email"
|
|
846
926
|
value={emailCc}
|
|
@@ -848,9 +928,9 @@ export function ChatComposer({
|
|
|
848
928
|
placeholder="CC email"
|
|
849
929
|
className="min-w-0 flex-1 bg-transparent text-base text-foreground outline-none placeholder:text-muted-foreground"
|
|
850
930
|
/>
|
|
851
|
-
</
|
|
931
|
+
</ComposerEmailFieldRow>
|
|
852
932
|
)}
|
|
853
|
-
<
|
|
933
|
+
<ComposerEmailFieldRow label="Subject">
|
|
854
934
|
<input
|
|
855
935
|
type="text"
|
|
856
936
|
value={emailSubject}
|
|
@@ -858,49 +938,47 @@ export function ChatComposer({
|
|
|
858
938
|
placeholder="Email subject"
|
|
859
939
|
className="min-w-0 flex-1 bg-transparent text-base text-foreground outline-none placeholder:text-muted-foreground"
|
|
860
940
|
/>
|
|
861
|
-
</
|
|
862
|
-
<
|
|
863
|
-
value={inputValue}
|
|
864
|
-
onChange={(e) => onInputChange?.(e.target.value)}
|
|
865
|
-
placeholder="Write your email..."
|
|
866
|
-
rows={6}
|
|
867
|
-
className="resize-y border-0 px-4 py-3 text-base shadow-none focus-visible:ring-0"
|
|
868
|
-
/>
|
|
941
|
+
</ComposerEmailFieldRow>
|
|
942
|
+
<EditorContent editor={editor} />
|
|
869
943
|
<div className="flex items-center justify-between border-t border-border px-3 py-2">
|
|
870
944
|
<div className="flex items-center gap-0.5">
|
|
871
|
-
<
|
|
945
|
+
<ComposerToolbarButton
|
|
872
946
|
label="Bold"
|
|
873
947
|
icon={Bold}
|
|
874
|
-
pressed={bold}
|
|
875
|
-
onToggle={() =>
|
|
948
|
+
pressed={editor?.isActive("bold")}
|
|
949
|
+
onToggle={() => editor?.chain().focus().toggleBold().run()}
|
|
876
950
|
/>
|
|
877
|
-
<
|
|
951
|
+
<ComposerToolbarButton
|
|
878
952
|
label="Italic"
|
|
879
953
|
icon={Italic}
|
|
880
|
-
pressed={italic}
|
|
881
|
-
onToggle={() =>
|
|
954
|
+
pressed={editor?.isActive("italic")}
|
|
955
|
+
onToggle={() => editor?.chain().focus().toggleItalic().run()}
|
|
882
956
|
/>
|
|
883
|
-
<
|
|
957
|
+
<ComposerToolbarButton
|
|
884
958
|
label="Underline"
|
|
885
959
|
icon={Underline}
|
|
886
|
-
pressed={underline}
|
|
887
|
-
onToggle={() =>
|
|
960
|
+
pressed={editor?.isActive("underline")}
|
|
961
|
+
onToggle={() =>
|
|
962
|
+
editor?.chain().focus().toggleUnderline().run()
|
|
963
|
+
}
|
|
888
964
|
/>
|
|
889
965
|
<Separator orientation="vertical" className="mx-1.5 h-4" />
|
|
890
|
-
<
|
|
891
|
-
<
|
|
966
|
+
<ComposerLinkPopover editor={editor} />
|
|
967
|
+
<ComposerToolbarButton label="Attach file" icon={Paperclip} />
|
|
892
968
|
</div>
|
|
893
969
|
<Button
|
|
894
970
|
size="sm"
|
|
895
|
-
onClick={() =>
|
|
971
|
+
onClick={() => {
|
|
972
|
+
const html = editor?.getHTML() ?? "";
|
|
896
973
|
onSendEmail?.({
|
|
897
|
-
content:
|
|
974
|
+
content: html,
|
|
898
975
|
to: emailTo,
|
|
899
976
|
cc: emailCc,
|
|
900
977
|
subject: emailSubject,
|
|
901
|
-
})
|
|
902
|
-
|
|
903
|
-
|
|
978
|
+
});
|
|
979
|
+
editor?.commands.clearContent();
|
|
980
|
+
}}
|
|
981
|
+
disabled={!editor || editor.isEmpty || !emailTo.trim()}
|
|
904
982
|
>
|
|
905
983
|
<Send className="mr-1.5 size-3.5" />
|
|
906
984
|
Send Email
|
|
@@ -2,9 +2,17 @@ import { type ReactElement } from "react";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
|
-
export type LabelProps = React.ComponentProps<"label"
|
|
5
|
+
export type LabelProps = React.ComponentProps<"label"> & {
|
|
6
|
+
/** When true, renders a red asterisk after the label text to indicate a required field */
|
|
7
|
+
required?: boolean;
|
|
8
|
+
};
|
|
6
9
|
|
|
7
|
-
function Label({
|
|
10
|
+
function Label({
|
|
11
|
+
className,
|
|
12
|
+
required,
|
|
13
|
+
children,
|
|
14
|
+
...props
|
|
15
|
+
}: LabelProps): ReactElement {
|
|
8
16
|
return (
|
|
9
17
|
// eslint-disable-next-line jsx-a11y/label-has-associated-control -- htmlFor is passed by the consumer
|
|
10
18
|
<label
|
|
@@ -14,7 +22,14 @@ function Label({ className, ...props }: LabelProps): ReactElement {
|
|
|
14
22
|
)}
|
|
15
23
|
data-slot="label"
|
|
16
24
|
{...props}
|
|
17
|
-
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
{required && (
|
|
28
|
+
<span aria-hidden="true" className="text-destructive">
|
|
29
|
+
*
|
|
30
|
+
</span>
|
|
31
|
+
)}
|
|
32
|
+
</label>
|
|
18
33
|
);
|
|
19
34
|
}
|
|
20
35
|
|