@groupher/rich-editor 0.0.1
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/README.md +69 -0
- package/components.json +21 -0
- package/dist/rich-editor.css +1 -0
- package/dist/rich-editor.es.js +60825 -0
- package/dist/rich-editor.umd.js +361 -0
- package/dist/vite.svg +1 -0
- package/eslint.config.js +26 -0
- package/index.html +13 -0
- package/package.json +54 -0
- package/public/vite.svg +1 -0
- package/src/RichEditor.tsx +102 -0
- package/src/assets/react.svg +1 -0
- package/src/components/editor/plate-editor.tsx +54 -0
- package/src/components/editor/plugins/basic-blocks-base-kit.tsx +35 -0
- package/src/components/editor/plugins/basic-blocks-kit.tsx +88 -0
- package/src/components/editor/plugins/basic-marks-base-kit.tsx +27 -0
- package/src/components/editor/plugins/basic-marks-kit.tsx +41 -0
- package/src/components/editor/plugins/basic-nodes-kit.tsx +6 -0
- package/src/components/ui/blockquote-node-static.tsx +11 -0
- package/src/components/ui/blockquote-node.tsx +13 -0
- package/src/components/ui/button.tsx +59 -0
- package/src/components/ui/code-node-static.tsx +15 -0
- package/src/components/ui/code-node.tsx +17 -0
- package/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/components/ui/editor-static.tsx +53 -0
- package/src/components/ui/editor.tsx +129 -0
- package/src/components/ui/fixed-toolbar.tsx +17 -0
- package/src/components/ui/heading-node-static.tsx +66 -0
- package/src/components/ui/heading-node.tsx +58 -0
- package/src/components/ui/highlight-node-static.tsx +11 -0
- package/src/components/ui/highlight-node.tsx +13 -0
- package/src/components/ui/hr-node-static.tsx +20 -0
- package/src/components/ui/hr-node.tsx +33 -0
- package/src/components/ui/kbd-node-static.tsx +15 -0
- package/src/components/ui/kbd-node.tsx +17 -0
- package/src/components/ui/mark-toolbar-button.tsx +19 -0
- package/src/components/ui/paragraph-node-static.tsx +13 -0
- package/src/components/ui/paragraph-node.tsx +15 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/toolbar.tsx +389 -0
- package/src/components/ui/tooltip.tsx +59 -0
- package/src/global.css +235 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +11 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +31 -0
- package/tsconfig.json +10 -0
- package/tsconfig.node.json +25 -0
- package/vite.config.ts +40 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { PlateLeafProps } from 'platejs/react';
|
|
4
|
+
|
|
5
|
+
import { PlateLeaf } from 'platejs/react';
|
|
6
|
+
|
|
7
|
+
export function KbdLeaf(props: PlateLeafProps) {
|
|
8
|
+
return (
|
|
9
|
+
<PlateLeaf
|
|
10
|
+
{...props}
|
|
11
|
+
as="kbd"
|
|
12
|
+
className="rounded border border-border bg-muted px-1.5 py-0.5 font-mono text-sm shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(248,_249,_250)_0px_1px_5px_0px_inset,_rgb(193,_200,_205)_0px_0px_0px_0.5px,_rgb(193,_200,_205)_0px_2px_1px_-1px,_rgb(193,_200,_205)_0px_1px_0px_0px] dark:shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(26,_29,_30)_0px_1px_5px_0px_inset,_rgb(76,_81,_85)_0px_0px_0px_0.5px,_rgb(76,_81,_85)_0px_2px_1px_-1px,_rgb(76,_81,_85)_0px_1px_0px_0px]"
|
|
13
|
+
>
|
|
14
|
+
{props.children}
|
|
15
|
+
</PlateLeaf>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMarkToolbarButton, useMarkToolbarButtonState } from 'platejs/react';
|
|
4
|
+
|
|
5
|
+
import { ToolbarButton } from './toolbar';
|
|
6
|
+
|
|
7
|
+
export function MarkToolbarButton({
|
|
8
|
+
clear,
|
|
9
|
+
nodeType,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof ToolbarButton> & {
|
|
12
|
+
nodeType: string;
|
|
13
|
+
clear?: string[] | string;
|
|
14
|
+
}) {
|
|
15
|
+
const state = useMarkToolbarButtonState({ clear, nodeType });
|
|
16
|
+
const { props: buttonProps } = useMarkToolbarButton(state);
|
|
17
|
+
|
|
18
|
+
return <ToolbarButton {...props} {...buttonProps} />;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SlateElementProps } from 'platejs';
|
|
2
|
+
|
|
3
|
+
import { SlateElement } from 'platejs';
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
export function ParagraphElementStatic(props: SlateElementProps) {
|
|
8
|
+
return (
|
|
9
|
+
<SlateElement {...props} className={cn('m-0 px-0 py-1')}>
|
|
10
|
+
{props.children}
|
|
11
|
+
</SlateElement>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { PlateElementProps } from 'platejs/react';
|
|
4
|
+
|
|
5
|
+
import { PlateElement } from 'platejs/react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
export function ParagraphElement(props: PlateElementProps) {
|
|
10
|
+
return (
|
|
11
|
+
<PlateElement {...props} className={cn('m-0 px-0 py-1')}>
|
|
12
|
+
{props.children}
|
|
13
|
+
</PlateElement>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Separator({
|
|
9
|
+
className,
|
|
10
|
+
orientation = "horizontal",
|
|
11
|
+
decorative = true,
|
|
12
|
+
...props
|
|
13
|
+
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
|
14
|
+
return (
|
|
15
|
+
<SeparatorPrimitive.Root
|
|
16
|
+
data-slot="separator"
|
|
17
|
+
decorative={decorative}
|
|
18
|
+
orientation={orientation}
|
|
19
|
+
className={cn(
|
|
20
|
+
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { Separator }
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
import * as ToolbarPrimitive from '@radix-ui/react-toolbar';
|
|
6
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
7
|
+
import { type VariantProps, cva } from 'class-variance-authority';
|
|
8
|
+
import { ChevronDown } from 'lucide-react';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
DropdownMenuLabel,
|
|
12
|
+
DropdownMenuRadioGroup,
|
|
13
|
+
DropdownMenuSeparator,
|
|
14
|
+
} from '@/components/ui/dropdown-menu';
|
|
15
|
+
import { Separator } from '@/components/ui/separator';
|
|
16
|
+
import { Tooltip, TooltipTrigger } from '@/components/ui/tooltip';
|
|
17
|
+
import { cn } from '@/lib/utils';
|
|
18
|
+
|
|
19
|
+
export function Toolbar({
|
|
20
|
+
className,
|
|
21
|
+
...props
|
|
22
|
+
}: React.ComponentProps<typeof ToolbarPrimitive.Root>) {
|
|
23
|
+
return (
|
|
24
|
+
<ToolbarPrimitive.Root
|
|
25
|
+
className={cn('relative flex items-center select-none', className)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function ToolbarToggleGroup({
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof ToolbarPrimitive.ToolbarToggleGroup>) {
|
|
35
|
+
return (
|
|
36
|
+
<ToolbarPrimitive.ToolbarToggleGroup
|
|
37
|
+
className={cn('flex items-center', className)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function ToolbarLink({
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<typeof ToolbarPrimitive.Link>) {
|
|
47
|
+
return (
|
|
48
|
+
<ToolbarPrimitive.Link
|
|
49
|
+
className={cn('font-medium underline underline-offset-4', className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function ToolbarSeparator({
|
|
56
|
+
className,
|
|
57
|
+
...props
|
|
58
|
+
}: React.ComponentProps<typeof ToolbarPrimitive.Separator>) {
|
|
59
|
+
return (
|
|
60
|
+
<ToolbarPrimitive.Separator
|
|
61
|
+
className={cn('mx-2 my-1 w-px shrink-0 bg-border', className)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// From toggleVariants
|
|
68
|
+
const toolbarButtonVariants = cva(
|
|
69
|
+
"inline-flex cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-checked:bg-accent aria-checked:text-accent-foreground aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
70
|
+
{
|
|
71
|
+
defaultVariants: {
|
|
72
|
+
size: 'default',
|
|
73
|
+
variant: 'default',
|
|
74
|
+
},
|
|
75
|
+
variants: {
|
|
76
|
+
size: {
|
|
77
|
+
default: 'h-9 min-w-9 px-2',
|
|
78
|
+
lg: 'h-10 min-w-10 px-2.5',
|
|
79
|
+
sm: 'h-8 min-w-8 px-1.5',
|
|
80
|
+
},
|
|
81
|
+
variant: {
|
|
82
|
+
default: 'bg-transparent',
|
|
83
|
+
outline:
|
|
84
|
+
'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const dropdownArrowVariants = cva(
|
|
91
|
+
cn(
|
|
92
|
+
'inline-flex items-center justify-center rounded-r-md text-sm font-medium text-foreground transition-colors disabled:pointer-events-none disabled:opacity-50'
|
|
93
|
+
),
|
|
94
|
+
{
|
|
95
|
+
defaultVariants: {
|
|
96
|
+
size: 'sm',
|
|
97
|
+
variant: 'default',
|
|
98
|
+
},
|
|
99
|
+
variants: {
|
|
100
|
+
size: {
|
|
101
|
+
default: 'h-9 w-6',
|
|
102
|
+
lg: 'h-10 w-8',
|
|
103
|
+
sm: 'h-8 w-4',
|
|
104
|
+
},
|
|
105
|
+
variant: {
|
|
106
|
+
default:
|
|
107
|
+
'bg-transparent hover:bg-muted hover:text-muted-foreground aria-checked:bg-accent aria-checked:text-accent-foreground',
|
|
108
|
+
outline:
|
|
109
|
+
'border border-l-0 border-input bg-transparent hover:bg-accent hover:text-accent-foreground',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
type ToolbarButtonProps = {
|
|
116
|
+
isDropdown?: boolean;
|
|
117
|
+
pressed?: boolean;
|
|
118
|
+
} & Omit<
|
|
119
|
+
React.ComponentPropsWithoutRef<typeof ToolbarToggleItem>,
|
|
120
|
+
'asChild' | 'value'
|
|
121
|
+
> &
|
|
122
|
+
VariantProps<typeof toolbarButtonVariants>;
|
|
123
|
+
|
|
124
|
+
export const ToolbarButton = withTooltip(function ToolbarButton({
|
|
125
|
+
children,
|
|
126
|
+
className,
|
|
127
|
+
isDropdown,
|
|
128
|
+
pressed,
|
|
129
|
+
size = 'sm',
|
|
130
|
+
variant,
|
|
131
|
+
...props
|
|
132
|
+
}: ToolbarButtonProps) {
|
|
133
|
+
return typeof pressed === 'boolean' ? (
|
|
134
|
+
<ToolbarToggleGroup disabled={props.disabled} value="single" type="single">
|
|
135
|
+
<ToolbarToggleItem
|
|
136
|
+
className={cn(
|
|
137
|
+
toolbarButtonVariants({
|
|
138
|
+
size,
|
|
139
|
+
variant,
|
|
140
|
+
}),
|
|
141
|
+
isDropdown && 'justify-between gap-1 pr-1',
|
|
142
|
+
className
|
|
143
|
+
)}
|
|
144
|
+
value={pressed ? 'single' : ''}
|
|
145
|
+
{...props}
|
|
146
|
+
>
|
|
147
|
+
{isDropdown ? (
|
|
148
|
+
<>
|
|
149
|
+
<div className="flex flex-1 items-center gap-2 whitespace-nowrap">
|
|
150
|
+
{children}
|
|
151
|
+
</div>
|
|
152
|
+
<div>
|
|
153
|
+
<ChevronDown
|
|
154
|
+
className="size-3.5 text-muted-foreground"
|
|
155
|
+
data-icon
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
</>
|
|
159
|
+
) : (
|
|
160
|
+
children
|
|
161
|
+
)}
|
|
162
|
+
</ToolbarToggleItem>
|
|
163
|
+
</ToolbarToggleGroup>
|
|
164
|
+
) : (
|
|
165
|
+
<ToolbarPrimitive.Button
|
|
166
|
+
className={cn(
|
|
167
|
+
toolbarButtonVariants({
|
|
168
|
+
size,
|
|
169
|
+
variant,
|
|
170
|
+
}),
|
|
171
|
+
isDropdown && 'pr-1',
|
|
172
|
+
className
|
|
173
|
+
)}
|
|
174
|
+
{...props}
|
|
175
|
+
>
|
|
176
|
+
{children}
|
|
177
|
+
</ToolbarPrimitive.Button>
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export function ToolbarSplitButton({
|
|
182
|
+
className,
|
|
183
|
+
...props
|
|
184
|
+
}: React.ComponentPropsWithoutRef<typeof ToolbarButton>) {
|
|
185
|
+
return (
|
|
186
|
+
<ToolbarButton
|
|
187
|
+
className={cn('group flex gap-0 px-0 hover:bg-transparent', className)}
|
|
188
|
+
{...props}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
type ToolbarSplitButtonPrimaryProps = Omit<
|
|
194
|
+
React.ComponentPropsWithoutRef<typeof ToolbarToggleItem>,
|
|
195
|
+
'value'
|
|
196
|
+
> &
|
|
197
|
+
VariantProps<typeof toolbarButtonVariants>;
|
|
198
|
+
|
|
199
|
+
export function ToolbarSplitButtonPrimary({
|
|
200
|
+
children,
|
|
201
|
+
className,
|
|
202
|
+
size = 'sm',
|
|
203
|
+
variant,
|
|
204
|
+
...props
|
|
205
|
+
}: ToolbarSplitButtonPrimaryProps) {
|
|
206
|
+
return (
|
|
207
|
+
<span
|
|
208
|
+
className={cn(
|
|
209
|
+
toolbarButtonVariants({
|
|
210
|
+
size,
|
|
211
|
+
variant,
|
|
212
|
+
}),
|
|
213
|
+
'rounded-r-none',
|
|
214
|
+
'group-data-[pressed=true]:bg-accent group-data-[pressed=true]:text-accent-foreground',
|
|
215
|
+
className
|
|
216
|
+
)}
|
|
217
|
+
{...props}
|
|
218
|
+
>
|
|
219
|
+
{children}
|
|
220
|
+
</span>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function ToolbarSplitButtonSecondary({
|
|
225
|
+
className,
|
|
226
|
+
size,
|
|
227
|
+
variant,
|
|
228
|
+
...props
|
|
229
|
+
}: React.ComponentPropsWithoutRef<'span'> &
|
|
230
|
+
VariantProps<typeof dropdownArrowVariants>) {
|
|
231
|
+
return (
|
|
232
|
+
<span
|
|
233
|
+
className={cn(
|
|
234
|
+
dropdownArrowVariants({
|
|
235
|
+
size,
|
|
236
|
+
variant,
|
|
237
|
+
}),
|
|
238
|
+
'group-data-[pressed=true]:bg-accent group-data-[pressed=true]:text-accent-foreground',
|
|
239
|
+
className
|
|
240
|
+
)}
|
|
241
|
+
onClick={(e) => e.stopPropagation()}
|
|
242
|
+
role="button"
|
|
243
|
+
{...props}
|
|
244
|
+
>
|
|
245
|
+
<ChevronDown className="size-3.5 text-muted-foreground" data-icon />
|
|
246
|
+
</span>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function ToolbarToggleItem({
|
|
251
|
+
className,
|
|
252
|
+
size = 'sm',
|
|
253
|
+
variant,
|
|
254
|
+
...props
|
|
255
|
+
}: React.ComponentProps<typeof ToolbarPrimitive.ToggleItem> &
|
|
256
|
+
VariantProps<typeof toolbarButtonVariants>) {
|
|
257
|
+
return (
|
|
258
|
+
<ToolbarPrimitive.ToggleItem
|
|
259
|
+
className={cn(toolbarButtonVariants({ size, variant }), className)}
|
|
260
|
+
{...props}
|
|
261
|
+
/>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function ToolbarGroup({
|
|
266
|
+
children,
|
|
267
|
+
className,
|
|
268
|
+
}: React.ComponentProps<'div'>) {
|
|
269
|
+
return (
|
|
270
|
+
<div
|
|
271
|
+
className={cn(
|
|
272
|
+
'group/toolbar-group',
|
|
273
|
+
'relative hidden has-[button]:flex',
|
|
274
|
+
className
|
|
275
|
+
)}
|
|
276
|
+
>
|
|
277
|
+
<div className="flex items-center">{children}</div>
|
|
278
|
+
|
|
279
|
+
<div className="mx-1.5 py-0.5 group-last/toolbar-group:hidden!">
|
|
280
|
+
<Separator orientation="vertical" />
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
type TooltipProps<T extends React.ElementType> = {
|
|
287
|
+
tooltip?: React.ReactNode;
|
|
288
|
+
tooltipContentProps?: Omit<
|
|
289
|
+
React.ComponentPropsWithoutRef<typeof TooltipContent>,
|
|
290
|
+
'children'
|
|
291
|
+
>;
|
|
292
|
+
tooltipProps?: Omit<
|
|
293
|
+
React.ComponentPropsWithoutRef<typeof Tooltip>,
|
|
294
|
+
'children'
|
|
295
|
+
>;
|
|
296
|
+
tooltipTriggerProps?: React.ComponentPropsWithoutRef<typeof TooltipTrigger>;
|
|
297
|
+
} & React.ComponentProps<T>;
|
|
298
|
+
|
|
299
|
+
function withTooltip<T extends React.ElementType>(Component: T) {
|
|
300
|
+
return function ExtendComponent({
|
|
301
|
+
tooltip,
|
|
302
|
+
tooltipContentProps,
|
|
303
|
+
tooltipProps,
|
|
304
|
+
tooltipTriggerProps,
|
|
305
|
+
...props
|
|
306
|
+
}: TooltipProps<T>) {
|
|
307
|
+
const [mounted, setMounted] = React.useState(false);
|
|
308
|
+
|
|
309
|
+
React.useEffect(() => {
|
|
310
|
+
setMounted(true);
|
|
311
|
+
}, []);
|
|
312
|
+
|
|
313
|
+
const component = <Component {...(props as React.ComponentProps<T>)} />;
|
|
314
|
+
|
|
315
|
+
if (tooltip && mounted) {
|
|
316
|
+
return (
|
|
317
|
+
<Tooltip {...tooltipProps}>
|
|
318
|
+
<TooltipTrigger asChild {...tooltipTriggerProps}>
|
|
319
|
+
{component}
|
|
320
|
+
</TooltipTrigger>
|
|
321
|
+
|
|
322
|
+
<TooltipContent {...tooltipContentProps}>{tooltip}</TooltipContent>
|
|
323
|
+
</Tooltip>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return component;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function TooltipContent({
|
|
332
|
+
children,
|
|
333
|
+
className,
|
|
334
|
+
// CHANGE
|
|
335
|
+
sideOffset = 4,
|
|
336
|
+
...props
|
|
337
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
338
|
+
return (
|
|
339
|
+
<TooltipPrimitive.Portal>
|
|
340
|
+
<TooltipPrimitive.Content
|
|
341
|
+
className={cn(
|
|
342
|
+
'z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md bg-primary px-3 py-1.5 text-xs text-balance text-primary-foreground',
|
|
343
|
+
className
|
|
344
|
+
)}
|
|
345
|
+
data-slot="tooltip-content"
|
|
346
|
+
sideOffset={sideOffset}
|
|
347
|
+
{...props}
|
|
348
|
+
>
|
|
349
|
+
{children}
|
|
350
|
+
{/* CHANGE */}
|
|
351
|
+
{/* <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" /> */}
|
|
352
|
+
</TooltipPrimitive.Content>
|
|
353
|
+
</TooltipPrimitive.Portal>
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function ToolbarMenuGroup({
|
|
358
|
+
children,
|
|
359
|
+
className,
|
|
360
|
+
label,
|
|
361
|
+
...props
|
|
362
|
+
}: React.ComponentProps<typeof DropdownMenuRadioGroup> & { label?: string }) {
|
|
363
|
+
return (
|
|
364
|
+
<>
|
|
365
|
+
<DropdownMenuSeparator
|
|
366
|
+
className={cn(
|
|
367
|
+
'hidden',
|
|
368
|
+
'mb-0 shrink-0 peer-has-[[role=menuitem]]/menu-group:block peer-has-[[role=menuitemradio]]/menu-group:block peer-has-[[role=option]]/menu-group:block'
|
|
369
|
+
)}
|
|
370
|
+
/>
|
|
371
|
+
|
|
372
|
+
<DropdownMenuRadioGroup
|
|
373
|
+
{...props}
|
|
374
|
+
className={cn(
|
|
375
|
+
'hidden',
|
|
376
|
+
'peer/menu-group group/menu-group my-1.5 has-[[role=menuitem]]:block has-[[role=menuitemradio]]:block has-[[role=option]]:block',
|
|
377
|
+
className
|
|
378
|
+
)}
|
|
379
|
+
>
|
|
380
|
+
{label && (
|
|
381
|
+
<DropdownMenuLabel className="text-xs font-semibold text-muted-foreground select-none">
|
|
382
|
+
{label}
|
|
383
|
+
</DropdownMenuLabel>
|
|
384
|
+
)}
|
|
385
|
+
{children}
|
|
386
|
+
</DropdownMenuRadioGroup>
|
|
387
|
+
</>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
function TooltipProvider({
|
|
7
|
+
delayDuration = 0,
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
10
|
+
return (
|
|
11
|
+
<TooltipPrimitive.Provider
|
|
12
|
+
data-slot="tooltip-provider"
|
|
13
|
+
delayDuration={delayDuration}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function Tooltip({
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
22
|
+
return (
|
|
23
|
+
<TooltipProvider>
|
|
24
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
</TooltipProvider>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function TooltipTrigger({
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
32
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function TooltipContent({
|
|
36
|
+
className,
|
|
37
|
+
sideOffset = 0,
|
|
38
|
+
children,
|
|
39
|
+
...props
|
|
40
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
41
|
+
return (
|
|
42
|
+
<TooltipPrimitive.Portal>
|
|
43
|
+
<TooltipPrimitive.Content
|
|
44
|
+
data-slot="tooltip-content"
|
|
45
|
+
sideOffset={sideOffset}
|
|
46
|
+
className={cn(
|
|
47
|
+
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
|
54
|
+
</TooltipPrimitive.Content>
|
|
55
|
+
</TooltipPrimitive.Portal>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|