a tool for shared writing and social publishing
1import React, { forwardRef, type JSX } from "react";
2import * as RadixTooltip from "@radix-ui/react-tooltip";
3import { theme } from "tailwind.config";
4
5import {
6 CardThemeProvider,
7 NestedCardThemeProvider,
8} from "./ThemeManager/ThemeProvider";
9import { useReplicache } from "src/replicache";
10import { PopoverArrow } from "./Icons/PopoverArrow";
11
12type ButtonProps = Omit<JSX.IntrinsicElements["button"], "content">;
13export const ButtonPrimary = forwardRef<
14 HTMLButtonElement,
15 ButtonProps & {
16 fullWidth?: boolean;
17 fullWidthOnMobile?: boolean;
18 children: React.ReactNode;
19 compact?: boolean;
20 }
21>((props, ref) => {
22 let {
23 className,
24 fullWidth,
25 fullWidthOnMobile,
26 compact,
27 children,
28 ...buttonProps
29 } = props;
30 return (
31 <button
32 {...buttonProps}
33 ref={ref}
34 className={`
35 m-0 h-max
36 ${fullWidth ? "w-full" : fullWidthOnMobile ? "w-full sm:w-max" : "w-max"}
37 ${compact ? "py-0 px-1" : "px-2 py-0.5 "}
38 bg-accent-1 outline-transparent border border-accent-1
39 rounded-md text-base font-bold text-accent-2
40 flex gap-2 items-center justify-center shrink-0
41 transparent-outline focus:outline-accent-1 hover:outline-accent-1 outline-offset-1
42 disabled:bg-border-light disabled:border-border-light disabled:text-border disabled:hover:text-border
43 ${className}
44 `}
45 >
46 {children}
47 </button>
48 );
49});
50ButtonPrimary.displayName = "ButtonPrimary";
51
52export const ButtonSecondary = forwardRef<
53 HTMLButtonElement,
54 ButtonProps & {
55 fullWidth?: boolean;
56 fullWidthOnMobile?: boolean;
57 children: React.ReactNode;
58 compact?: boolean;
59 }
60>((props, ref) => {
61 let {
62 className,
63 fullWidth,
64 fullWidthOnMobile,
65 compact,
66 children,
67 ...buttonProps
68 } = props;
69 return (
70 <button
71 {...buttonProps}
72 ref={ref}
73 className={`m-0 h-max
74 ${fullWidth ? "w-full" : fullWidthOnMobile ? "w-full sm:w-max" : "w-max"}
75 ${props.compact ? "py-0 px-1" : "px-2 py-0.5 "}
76 bg-bg-page outline-transparent
77 rounded-md text-base font-bold text-accent-contrast
78 flex gap-2 items-center justify-center shrink-0
79 transparent-outline focus:outline-accent-contrast hover:outline-accent-contrast outline-offset-1
80 border border-accent-contrast
81 disabled:bg-border-light disabled:text-border disabled:hover:text-border
82 ${props.className}
83`}
84 >
85 {props.children}
86 </button>
87 );
88});
89ButtonSecondary.displayName = "ButtonSecondary";
90
91export const ButtonTertiary = forwardRef<
92 HTMLButtonElement,
93 {
94 fullWidth?: boolean;
95 children: React.ReactNode;
96 compact?: boolean;
97 } & ButtonProps
98>((props, ref) => {
99 let { fullWidth, children, compact, ...buttonProps } = props;
100 return (
101 <button
102 {...buttonProps}
103 ref={ref}
104 className={`m-0 h-max ${fullWidth ? "w-full" : "w-max"} ${compact ? "px-0" : "px-1"}
105 bg-transparent text-base font-bold text-accent-contrast
106 flex gap-2 items-center justify-center shrink-0
107 hover:underline disabled:text-border
108 ${props.className}
109`}
110 >
111 {children}
112 </button>
113 );
114});
115ButtonTertiary.displayName = "ButtonTertiary";
116
117export const TooltipButton = (props: {
118 onMouseDown?: (e: React.MouseEvent) => void | Promise<void>;
119 disabled?: boolean;
120 className?: string;
121 children: React.ReactNode;
122 tooltipContent: React.ReactNode;
123 side?: "top" | "right" | "bottom" | "left" | undefined;
124 open?: boolean;
125 delayDuration?: number;
126}) => {
127 let { undoManager } = useReplicache();
128 return (
129 // toolbar button does not control the highlight theme setter
130 // if toolbar button is updated, be sure to update there as well
131 <RadixTooltip.TooltipProvider
132 delayDuration={props.delayDuration ? props.delayDuration : 400}
133 >
134 <RadixTooltip.Root open={props.open}>
135 <RadixTooltip.Trigger
136 disabled={props.disabled}
137 className={props.className}
138 onMouseDown={async (e) => {
139 e.preventDefault();
140 undoManager.startGroup();
141 props.onMouseDown && (await props.onMouseDown(e));
142 undoManager.endGroup();
143 }}
144 >
145 {props.children}
146 </RadixTooltip.Trigger>
147
148 <RadixTooltip.Portal>
149 <NestedCardThemeProvider>
150 <RadixTooltip.Content
151 side={props.side ? props.side : undefined}
152 sideOffset={6}
153 alignOffset={12}
154 className="z-10 bg-border rounded-md py-1 px-[6px] font-bold text-secondary text-sm"
155 >
156 {props.tooltipContent}
157 <RadixTooltip.Arrow
158 asChild
159 width={16}
160 height={8}
161 viewBox="0 0 16 8"
162 >
163 <PopoverArrow
164 arrowFill={theme.colors["border"]}
165 arrowStroke="transparent"
166 />
167 </RadixTooltip.Arrow>
168 </RadixTooltip.Content>
169 </NestedCardThemeProvider>
170 </RadixTooltip.Portal>
171 </RadixTooltip.Root>
172 </RadixTooltip.TooltipProvider>
173 );
174};