@blocknote/shadcn 0.13.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 (75) hide show
  1. package/LICENSE +373 -0
  2. package/dist/blocknote-shadcn.js +1881 -0
  3. package/dist/blocknote-shadcn.js.map +1 -0
  4. package/dist/blocknote-shadcn.umd.cjs +28 -0
  5. package/dist/blocknote-shadcn.umd.cjs.map +1 -0
  6. package/dist/style.css +1 -0
  7. package/dist/webpack-stats.json +1 -0
  8. package/package.json +104 -0
  9. package/src/ShadCNComponentsContext.tsx +39 -0
  10. package/src/components/ui/badge.tsx +36 -0
  11. package/src/components/ui/button.tsx +56 -0
  12. package/src/components/ui/card.tsx +86 -0
  13. package/src/components/ui/dropdown-menu.tsx +195 -0
  14. package/src/components/ui/form.tsx +176 -0
  15. package/src/components/ui/input.tsx +24 -0
  16. package/src/components/ui/label.tsx +24 -0
  17. package/src/components/ui/popover.tsx +29 -0
  18. package/src/components/ui/select.tsx +152 -0
  19. package/src/components/ui/tabs.tsx +53 -0
  20. package/src/components/ui/toggle.tsx +43 -0
  21. package/src/components/ui/tooltip.tsx +28 -0
  22. package/src/form/Form.tsx +21 -0
  23. package/src/form/TextInput.tsx +61 -0
  24. package/src/index.tsx +122 -0
  25. package/src/lib/utils.ts +6 -0
  26. package/src/menu/Menu.tsx +212 -0
  27. package/src/panel/Panel.tsx +54 -0
  28. package/src/panel/PanelButton.tsx +27 -0
  29. package/src/panel/PanelFileInput.tsx +27 -0
  30. package/src/panel/PanelTab.tsx +25 -0
  31. package/src/panel/PanelTextInput.tsx +29 -0
  32. package/src/popover/popover.tsx +69 -0
  33. package/src/sideMenu/SideMenu.tsx +18 -0
  34. package/src/sideMenu/SideMenuButton.tsx +45 -0
  35. package/src/style.css +109 -0
  36. package/src/suggestionMenu/SuggestionMenu.tsx +28 -0
  37. package/src/suggestionMenu/SuggestionMenuEmptyItem.tsx +26 -0
  38. package/src/suggestionMenu/SuggestionMenuItem.tsx +47 -0
  39. package/src/suggestionMenu/SuggestionMenuLabel.tsx +22 -0
  40. package/src/suggestionMenu/SuggestionMenuLoader.tsx +18 -0
  41. package/src/tableHandle/TableHandle.tsx +43 -0
  42. package/src/toolbar/Toolbar.tsx +153 -0
  43. package/types/src/ShadCNComponentsContext.d.ts +56 -0
  44. package/types/src/components/ui/badge.d.ts +9 -0
  45. package/types/src/components/ui/button.d.ts +11 -0
  46. package/types/src/components/ui/card.d.ts +8 -0
  47. package/types/src/components/ui/dropdown-menu.d.ts +27 -0
  48. package/types/src/components/ui/form.d.ts +23 -0
  49. package/types/src/components/ui/input.d.ts +4 -0
  50. package/types/src/components/ui/label.d.ts +5 -0
  51. package/types/src/components/ui/popover.d.ts +6 -0
  52. package/types/src/components/ui/select.d.ts +13 -0
  53. package/types/src/components/ui/tabs.d.ts +7 -0
  54. package/types/src/components/ui/toggle.d.ts +12 -0
  55. package/types/src/components/ui/tooltip.d.ts +7 -0
  56. package/types/src/form/Form.d.ts +2 -0
  57. package/types/src/form/TextInput.d.ts +13 -0
  58. package/types/src/index.d.ts +12 -0
  59. package/types/src/lib/utils.d.ts +2 -0
  60. package/types/src/menu/Menu.d.ts +24 -0
  61. package/types/src/panel/Panel.d.ts +12 -0
  62. package/types/src/panel/PanelButton.d.ts +11 -0
  63. package/types/src/panel/PanelFileInput.d.ts +7 -0
  64. package/types/src/panel/PanelTab.d.ts +5 -0
  65. package/types/src/panel/PanelTextInput.d.ts +8 -0
  66. package/types/src/popover/popover.d.ts +11 -0
  67. package/types/src/sideMenu/SideMenu.d.ts +5 -0
  68. package/types/src/sideMenu/SideMenuButton.d.ts +15 -0
  69. package/types/src/suggestionMenu/SuggestionMenu.d.ts +6 -0
  70. package/types/src/suggestionMenu/SuggestionMenuEmptyItem.d.ts +5 -0
  71. package/types/src/suggestionMenu/SuggestionMenuItem.d.ts +8 -0
  72. package/types/src/suggestionMenu/SuggestionMenuLabel.d.ts +5 -0
  73. package/types/src/suggestionMenu/SuggestionMenuLoader.d.ts +5 -0
  74. package/types/src/tableHandle/TableHandle.d.ts +14 -0
  75. package/types/src/toolbar/Toolbar.d.ts +25 -0
@@ -0,0 +1,152 @@
1
+ import * as React from "react";
2
+ import * as SelectPrimitive from "@radix-ui/react-select";
3
+ import { Check, ChevronDown, ChevronUp } from "lucide-react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const Select = SelectPrimitive.Root;
8
+
9
+ const SelectGroup = SelectPrimitive.Group;
10
+
11
+ const SelectValue = SelectPrimitive.Value;
12
+
13
+ const SelectTrigger = React.forwardRef<
14
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
15
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
16
+ >(({ className, children, ...props }, ref) => (
17
+ <SelectPrimitive.Trigger
18
+ ref={ref}
19
+ className={cn(
20
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
21
+ className
22
+ )}
23
+ {...props}>
24
+ {children}
25
+ <SelectPrimitive.Icon asChild>
26
+ <ChevronDown className="h-4 w-4 opacity-50" />
27
+ </SelectPrimitive.Icon>
28
+ </SelectPrimitive.Trigger>
29
+ ));
30
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
31
+
32
+ const SelectScrollUpButton = React.forwardRef<
33
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
34
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
35
+ >(({ className, ...props }, ref) => (
36
+ <SelectPrimitive.ScrollUpButton
37
+ ref={ref}
38
+ className={cn(
39
+ "flex cursor-default items-center justify-center py-1",
40
+ className
41
+ )}
42
+ {...props}>
43
+ <ChevronUp className="h-4 w-4" />
44
+ </SelectPrimitive.ScrollUpButton>
45
+ ));
46
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
47
+
48
+ const SelectScrollDownButton = React.forwardRef<
49
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
50
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
51
+ >(({ className, ...props }, ref) => (
52
+ <SelectPrimitive.ScrollDownButton
53
+ ref={ref}
54
+ className={cn(
55
+ "flex cursor-default items-center justify-center py-1",
56
+ className
57
+ )}
58
+ {...props}>
59
+ <ChevronDown className="h-4 w-4" />
60
+ </SelectPrimitive.ScrollDownButton>
61
+ ));
62
+ SelectScrollDownButton.displayName =
63
+ SelectPrimitive.ScrollDownButton.displayName;
64
+
65
+ const SelectContent = React.forwardRef<
66
+ React.ElementRef<typeof SelectPrimitive.Content>,
67
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
68
+ >(({ className, children, position = "popper", ...props }, ref) => (
69
+ // <SelectPrimitive.Portal>
70
+ <SelectPrimitive.Content
71
+ ref={ref}
72
+ className={cn(
73
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
74
+ position === "popper" &&
75
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
76
+ className
77
+ )}
78
+ position={position}
79
+ {...props}>
80
+ <SelectScrollUpButton />
81
+ <SelectPrimitive.Viewport
82
+ className={cn(
83
+ "p-1",
84
+ position === "popper" &&
85
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
86
+ )}>
87
+ {children}
88
+ </SelectPrimitive.Viewport>
89
+ <SelectScrollDownButton />
90
+ </SelectPrimitive.Content>
91
+ // </SelectPrimitive.Portal>
92
+ ));
93
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
94
+
95
+ const SelectLabel = React.forwardRef<
96
+ React.ElementRef<typeof SelectPrimitive.Label>,
97
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
98
+ >(({ className, ...props }, ref) => (
99
+ <SelectPrimitive.Label
100
+ ref={ref}
101
+ className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
102
+ {...props}
103
+ />
104
+ ));
105
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
106
+
107
+ const SelectItem = React.forwardRef<
108
+ React.ElementRef<typeof SelectPrimitive.Item>,
109
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
110
+ >(({ className, children, ...props }, ref) => (
111
+ <SelectPrimitive.Item
112
+ ref={ref}
113
+ className={cn(
114
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
115
+ className
116
+ )}
117
+ {...props}>
118
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
119
+ <SelectPrimitive.ItemIndicator>
120
+ <Check className="h-4 w-4" />
121
+ </SelectPrimitive.ItemIndicator>
122
+ </span>
123
+
124
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
125
+ </SelectPrimitive.Item>
126
+ ));
127
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
128
+
129
+ const SelectSeparator = React.forwardRef<
130
+ React.ElementRef<typeof SelectPrimitive.Separator>,
131
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
132
+ >(({ className, ...props }, ref) => (
133
+ <SelectPrimitive.Separator
134
+ ref={ref}
135
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
136
+ {...props}
137
+ />
138
+ ));
139
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
140
+
141
+ export {
142
+ Select,
143
+ SelectGroup,
144
+ SelectValue,
145
+ SelectTrigger,
146
+ SelectContent,
147
+ SelectLabel,
148
+ SelectItem,
149
+ SelectSeparator,
150
+ SelectScrollUpButton,
151
+ SelectScrollDownButton,
152
+ };
@@ -0,0 +1,53 @@
1
+ import * as React from "react";
2
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ const Tabs = TabsPrimitive.Root;
7
+
8
+ const TabsList = React.forwardRef<
9
+ React.ElementRef<typeof TabsPrimitive.List>,
10
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
11
+ >(({ className, ...props }, ref) => (
12
+ <TabsPrimitive.List
13
+ ref={ref}
14
+ className={cn(
15
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ ));
21
+ TabsList.displayName = TabsPrimitive.List.displayName;
22
+
23
+ const TabsTrigger = React.forwardRef<
24
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
25
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
26
+ >(({ className, ...props }, ref) => (
27
+ <TabsPrimitive.Trigger
28
+ ref={ref}
29
+ className={cn(
30
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
31
+ className
32
+ )}
33
+ {...props}
34
+ />
35
+ ));
36
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
37
+
38
+ const TabsContent = React.forwardRef<
39
+ React.ElementRef<typeof TabsPrimitive.Content>,
40
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
41
+ >(({ className, ...props }, ref) => (
42
+ <TabsPrimitive.Content
43
+ ref={ref}
44
+ className={cn(
45
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ ));
51
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
52
+
53
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,43 @@
1
+ import * as React from "react";
2
+ import * as TogglePrimitive from "@radix-ui/react-toggle";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const toggleVariants = cva(
8
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-transparent",
13
+ outline:
14
+ "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
15
+ },
16
+ size: {
17
+ default: "h-10 px-3",
18
+ sm: "h-9 px-2.5",
19
+ lg: "h-11 px-5",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ size: "default",
25
+ },
26
+ }
27
+ );
28
+
29
+ const Toggle = React.forwardRef<
30
+ React.ElementRef<typeof TogglePrimitive.Root>,
31
+ React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
32
+ VariantProps<typeof toggleVariants>
33
+ >(({ className, variant, size, ...props }, ref) => (
34
+ <TogglePrimitive.Root
35
+ ref={ref}
36
+ className={cn(toggleVariants({ variant, size, className }))}
37
+ {...props}
38
+ />
39
+ ));
40
+
41
+ Toggle.displayName = TogglePrimitive.Root.displayName;
42
+
43
+ export { Toggle, toggleVariants };
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ const TooltipProvider = TooltipPrimitive.Provider;
7
+
8
+ const Tooltip = TooltipPrimitive.Root;
9
+
10
+ const TooltipTrigger = TooltipPrimitive.Trigger;
11
+
12
+ const TooltipContent = React.forwardRef<
13
+ React.ElementRef<typeof TooltipPrimitive.Content>,
14
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
15
+ >(({ className, sideOffset = 4, ...props }, ref) => (
16
+ <TooltipPrimitive.Content
17
+ ref={ref}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md 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",
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ ));
26
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
27
+
28
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,21 @@
1
+ import { ComponentProps } from "@blocknote/react";
2
+
3
+ import { assertEmpty } from "@blocknote/core";
4
+ import { useForm } from "react-hook-form";
5
+ import { useShadCNComponentsContext } from "../ShadCNComponentsContext";
6
+
7
+ export const Form = (props: ComponentProps["Generic"]["Form"]["Root"]) => {
8
+ const { children, ...rest } = props;
9
+
10
+ assertEmpty(rest);
11
+
12
+ const ShadCNComponents = useShadCNComponentsContext()!;
13
+
14
+ const form = useForm();
15
+
16
+ return (
17
+ <ShadCNComponents.Form.Form {...form}>
18
+ {children}
19
+ </ShadCNComponents.Form.Form>
20
+ );
21
+ };
@@ -0,0 +1,61 @@
1
+ import { ComponentProps } from "@blocknote/react";
2
+ import { forwardRef } from "react";
3
+
4
+ import { assertEmpty } from "@blocknote/core";
5
+ import { useShadCNComponentsContext } from "../ShadCNComponentsContext";
6
+
7
+ export const TextInput = forwardRef(
8
+ (props: ComponentProps["Generic"]["Form"]["TextInput"]) => {
9
+ const {
10
+ className,
11
+ name,
12
+ label,
13
+ icon, // TODO: implement
14
+ value,
15
+ autoFocus,
16
+ placeholder,
17
+ onKeyDown,
18
+ onChange,
19
+ onSubmit,
20
+ ...rest
21
+ } = props;
22
+
23
+ assertEmpty(rest);
24
+
25
+ const ShadCNComponents = useShadCNComponentsContext()!;
26
+
27
+ if (!label) {
28
+ return (
29
+ <ShadCNComponents.Input.Input
30
+ aria-label={name}
31
+ name={name}
32
+ autoFocus={autoFocus}
33
+ placeholder={placeholder}
34
+ value={value}
35
+ onKeyDown={onKeyDown}
36
+ onChange={onChange}
37
+ onSubmit={onSubmit}
38
+ />
39
+ );
40
+ }
41
+
42
+ return (
43
+ <div>
44
+ <ShadCNComponents.Label.Label htmlFor={label}>
45
+ {label}
46
+ </ShadCNComponents.Label.Label>
47
+ <ShadCNComponents.Input.Input
48
+ className={className}
49
+ id={label}
50
+ name={name}
51
+ autoFocus={autoFocus}
52
+ placeholder={placeholder}
53
+ value={value}
54
+ onKeyDown={onKeyDown}
55
+ onChange={onChange}
56
+ onSubmit={onSubmit}
57
+ />
58
+ </div>
59
+ );
60
+ }
61
+ );
package/src/index.tsx ADDED
@@ -0,0 +1,122 @@
1
+ import { BlockSchema, InlineContentSchema, StyleSchema } from "@blocknote/core";
2
+ import {
3
+ BlockNoteViewRaw,
4
+ Components,
5
+ ComponentsContext,
6
+ } from "@blocknote/react";
7
+ import { ComponentProps, useMemo } from "react";
8
+
9
+ import {
10
+ ShadCNComponents,
11
+ ShadCNComponentsContext,
12
+ ShadCNDefaultComponents,
13
+ } from "./ShadCNComponentsContext";
14
+ import { Form } from "./form/Form";
15
+ import {
16
+ Menu,
17
+ MenuDivider,
18
+ MenuDropdown,
19
+ MenuItem,
20
+ MenuLabel,
21
+ MenuTrigger,
22
+ } from "./menu/Menu";
23
+ import { Panel } from "./panel/Panel";
24
+ import { PanelButton } from "./panel/PanelButton";
25
+ import { PanelFileInput } from "./panel/PanelFileInput";
26
+ import { PanelTab } from "./panel/PanelTab";
27
+ import { PanelTextInput } from "./panel/PanelTextInput";
28
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover/popover";
29
+ import { SideMenu } from "./sideMenu/SideMenu";
30
+ import { SideMenuButton } from "./sideMenu/SideMenuButton";
31
+ import { SuggestionMenu } from "./suggestionMenu/SuggestionMenu";
32
+ import { SuggestionMenuEmptyItem } from "./suggestionMenu/SuggestionMenuEmptyItem";
33
+ import { SuggestionMenuItem } from "./suggestionMenu/SuggestionMenuItem";
34
+ import { SuggestionMenuLabel } from "./suggestionMenu/SuggestionMenuLabel";
35
+ import { SuggestionMenuLoader } from "./suggestionMenu/SuggestionMenuLoader";
36
+ import { TableHandle } from "./tableHandle/TableHandle";
37
+ import { TextInput } from "./form/TextInput";
38
+ import { Toolbar, ToolbarButton, ToolbarSelect } from "./toolbar/Toolbar";
39
+
40
+ import "./style.css";
41
+
42
+ export const components: Components = {
43
+ FormattingToolbar: {
44
+ Root: Toolbar,
45
+ Button: ToolbarButton,
46
+ Select: ToolbarSelect,
47
+ },
48
+ ImagePanel: {
49
+ Root: Panel,
50
+ Button: PanelButton,
51
+ FileInput: PanelFileInput,
52
+ TabPanel: PanelTab,
53
+ TextInput: PanelTextInput,
54
+ },
55
+ LinkToolbar: {
56
+ Root: Toolbar,
57
+ Button: ToolbarButton,
58
+ },
59
+ SideMenu: {
60
+ Root: SideMenu,
61
+ Button: SideMenuButton,
62
+ },
63
+ SuggestionMenu: {
64
+ Root: SuggestionMenu,
65
+ Item: SuggestionMenuItem,
66
+ EmptyItem: SuggestionMenuEmptyItem,
67
+ Label: SuggestionMenuLabel,
68
+ Loader: SuggestionMenuLoader,
69
+ },
70
+ TableHandle: {
71
+ Root: TableHandle,
72
+ },
73
+ Generic: {
74
+ Form: {
75
+ Root: Form,
76
+ TextInput: TextInput,
77
+ },
78
+ Menu: {
79
+ Root: Menu,
80
+ Trigger: MenuTrigger,
81
+ Dropdown: MenuDropdown,
82
+ Divider: MenuDivider,
83
+ Label: MenuLabel,
84
+ Item: MenuItem,
85
+ },
86
+ Popover: {
87
+ Root: Popover,
88
+ Trigger: PopoverTrigger,
89
+ Content: PopoverContent,
90
+ },
91
+ },
92
+ };
93
+
94
+ export const BlockNoteView = <
95
+ BSchema extends BlockSchema,
96
+ ISchema extends InlineContentSchema,
97
+ SSchema extends StyleSchema
98
+ >(
99
+ props: ComponentProps<typeof BlockNoteViewRaw<BSchema, ISchema, SSchema>> & {
100
+ /**
101
+ * (optional)Provide your own shadcn component overrides
102
+ */
103
+ shadCNComponents?: Partial<ShadCNComponents>;
104
+ }
105
+ ) => {
106
+ const { shadCNComponents, ...rest } = props;
107
+
108
+ const componentsValue = useMemo(() => {
109
+ return {
110
+ ...shadCNComponents,
111
+ ...ShadCNDefaultComponents,
112
+ };
113
+ }, [shadCNComponents]);
114
+
115
+ return (
116
+ <ShadCNComponentsContext.Provider value={componentsValue}>
117
+ <ComponentsContext.Provider value={components}>
118
+ <BlockNoteViewRaw {...rest} />
119
+ </ComponentsContext.Provider>
120
+ </ShadCNComponentsContext.Provider>
121
+ );
122
+ };
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,212 @@
1
+ import type * as ShadCNDropdownMenu from "../components/ui/dropdown-menu";
2
+
3
+ import { assertEmpty } from "@blocknote/core";
4
+ import { ComponentProps } from "@blocknote/react";
5
+ import { ChevronRight } from "lucide-react";
6
+ import { forwardRef, useMemo } from "react";
7
+ import { useShadCNComponentsContext } from "../ShadCNComponentsContext";
8
+ import { cn } from "../lib/utils";
9
+
10
+ // hacky HoC to change DropdownMenuTrigger to open a menu on PointerUp instead of PointerDown
11
+ // Needed to fix this issue: https://github.com/radix-ui/primitives/issues/2867
12
+ const MenuTriggerWithPointerUp = (
13
+ Comp: typeof ShadCNDropdownMenu.DropdownMenuTrigger
14
+ ) =>
15
+ forwardRef<
16
+ any,
17
+ React.ComponentProps<typeof ShadCNDropdownMenu.DropdownMenuTrigger>
18
+ >((props, ref) => {
19
+ return (
20
+ <Comp
21
+ onPointerDown={(e) => {
22
+ if (!(e.nativeEvent as any).fakeEvent) {
23
+ // setting ctrlKey will block the menu from opening
24
+ // as it will block this line: https://github.com/radix-ui/primitives/blob/b32a93318cdfce383c2eec095710d35ffbd33a1c/packages/react/dropdown-menu/src/DropdownMenu.tsx#L120
25
+ e.ctrlKey = true;
26
+ }
27
+ }}
28
+ onPointerUp={(event) => {
29
+ // dispatch a pointerdown event so the Radix pointer down handler gets called that opens the menu
30
+ const e = new PointerEvent("pointerdown", event.nativeEvent);
31
+ (e as any).fakeEvent = true;
32
+ event.target.dispatchEvent(e);
33
+ }}
34
+ {...props}
35
+ ref={ref}
36
+ />
37
+ );
38
+ });
39
+
40
+ export const Menu = (props: ComponentProps["Generic"]["Menu"]["Root"]) => {
41
+ const {
42
+ children,
43
+ onOpenChange,
44
+ position, // Unused
45
+ sub,
46
+ ...rest
47
+ } = props;
48
+
49
+ assertEmpty(rest);
50
+
51
+ const ShadCNComponents = useShadCNComponentsContext()!;
52
+
53
+ if (sub) {
54
+ return (
55
+ <ShadCNComponents.DropdownMenu.DropdownMenuSub
56
+ onOpenChange={onOpenChange}>
57
+ {children}
58
+ </ShadCNComponents.DropdownMenu.DropdownMenuSub>
59
+ );
60
+ } else {
61
+ return (
62
+ <ShadCNComponents.DropdownMenu.DropdownMenu onOpenChange={onOpenChange}>
63
+ {children}
64
+ </ShadCNComponents.DropdownMenu.DropdownMenu>
65
+ );
66
+ }
67
+ };
68
+
69
+ export const MenuTrigger = (
70
+ props: ComponentProps["Generic"]["Menu"]["Trigger"]
71
+ ) => {
72
+ const { children, sub, ...rest } = props;
73
+
74
+ assertEmpty(rest);
75
+
76
+ const ShadCNComponents = useShadCNComponentsContext()!;
77
+
78
+ const DropdownMenuTrigger = useMemo(
79
+ () =>
80
+ MenuTriggerWithPointerUp(
81
+ ShadCNComponents.DropdownMenu.DropdownMenuTrigger
82
+ ),
83
+ [ShadCNComponents.DropdownMenu.DropdownMenuTrigger]
84
+ );
85
+
86
+ if (sub) {
87
+ return (
88
+ <ShadCNComponents.DropdownMenu.DropdownMenuSubTrigger>
89
+ {children}
90
+ </ShadCNComponents.DropdownMenu.DropdownMenuSubTrigger>
91
+ );
92
+ } else {
93
+ return (
94
+ <DropdownMenuTrigger asChild={true} {...rest}>
95
+ {children}
96
+ </DropdownMenuTrigger>
97
+ );
98
+ }
99
+ };
100
+
101
+ export const MenuDropdown = forwardRef<
102
+ HTMLDivElement,
103
+ ComponentProps["Generic"]["Menu"]["Dropdown"]
104
+ >((props, ref) => {
105
+ const { className, children, sub, ...rest } = props;
106
+
107
+ assertEmpty(rest);
108
+
109
+ const ShadCNComponents = useShadCNComponentsContext()!;
110
+
111
+ if (sub) {
112
+ return (
113
+ <ShadCNComponents.DropdownMenu.DropdownMenuSubContent
114
+ className={className}
115
+ ref={ref}>
116
+ {children}
117
+ </ShadCNComponents.DropdownMenu.DropdownMenuSubContent>
118
+ );
119
+ } else {
120
+ return (
121
+ <ShadCNComponents.DropdownMenu.DropdownMenuContent
122
+ className={className}
123
+ ref={ref}>
124
+ {children}
125
+ </ShadCNComponents.DropdownMenu.DropdownMenuContent>
126
+ );
127
+ }
128
+ });
129
+
130
+ export const MenuItem = forwardRef<
131
+ HTMLDivElement,
132
+ ComponentProps["Generic"]["Menu"]["Item"]
133
+ >((props, ref) => {
134
+ const { className, children, icon, checked, subTrigger, onClick, ...rest } =
135
+ props;
136
+
137
+ assertEmpty(rest);
138
+
139
+ const ShadCNComponents = useShadCNComponentsContext()!;
140
+
141
+ if (subTrigger) {
142
+ return (
143
+ <>
144
+ {icon}
145
+ {children}
146
+ </>
147
+ );
148
+ }
149
+
150
+ if (checked !== undefined) {
151
+ return (
152
+ <ShadCNComponents.DropdownMenu.DropdownMenuCheckboxItem
153
+ className={cn(className, "gap-1")}
154
+ ref={ref}
155
+ checked={checked}
156
+ onClick={onClick}
157
+ {...rest}>
158
+ {icon}
159
+ {children}
160
+ </ShadCNComponents.DropdownMenu.DropdownMenuCheckboxItem>
161
+ );
162
+ }
163
+
164
+ return (
165
+ <ShadCNComponents.DropdownMenu.DropdownMenuItem
166
+ className={className}
167
+ ref={ref}
168
+ onClick={onClick}
169
+ {...rest}>
170
+ {icon}
171
+ {children}
172
+ {subTrigger && <ChevronRight className="ml-auto h-4 w-4" />}
173
+ </ShadCNComponents.DropdownMenu.DropdownMenuItem>
174
+ );
175
+ });
176
+
177
+ export const MenuDivider = forwardRef<
178
+ HTMLDivElement,
179
+ ComponentProps["Generic"]["Menu"]["Divider"]
180
+ >((props, ref) => {
181
+ const { className, ...rest } = props;
182
+
183
+ assertEmpty(rest);
184
+
185
+ const ShadCNComponents = useShadCNComponentsContext()!;
186
+
187
+ return (
188
+ <ShadCNComponents.DropdownMenu.DropdownMenuSeparator
189
+ className={className}
190
+ ref={ref}
191
+ />
192
+ );
193
+ });
194
+
195
+ export const MenuLabel = forwardRef<
196
+ HTMLDivElement,
197
+ ComponentProps["Generic"]["Menu"]["Label"]
198
+ >((props, ref) => {
199
+ const { className, children, ...rest } = props;
200
+
201
+ assertEmpty(rest);
202
+
203
+ const ShadCNComponents = useShadCNComponentsContext()!;
204
+
205
+ return (
206
+ <ShadCNComponents.DropdownMenu.DropdownMenuLabel
207
+ className={className}
208
+ ref={ref}>
209
+ {children}
210
+ </ShadCNComponents.DropdownMenu.DropdownMenuLabel>
211
+ );
212
+ });