Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions apps/block-editor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import type { NodeWithPos } from "@tiptap/core"
import { Extension } from "@tiptap/core"
import type { EditorState, Transaction } from "@tiptap/pm/state"
import { getSelectedNodesOfType } from "@/lib/tiptap-utils"
import { updateNodesAttr } from "@/lib/tiptap-utils"

declare module "@tiptap/core" {
interface Commands<ReturnType> {
nodeBackground: {
setNodeBackgroundColor: (backgroundColor: string) => ReturnType
unsetNodeBackgroundColor: () => ReturnType
toggleNodeBackgroundColor: (backgroundColor: string) => ReturnType
}
}
}

export interface NodeBackgroundOptions {
/**
* Node types that should support background colors
* @default ["paragraph", "heading", "blockquote", "taskList", "bulletList", "orderedList", "tableCell", "tableHeader"]
*/
types: string[]
/**
* Use inline style instead of data attribute
* @default true
*/
useStyle?: boolean
}

/**
* Determines the target color for toggle operations
*/
function getToggleColor(
targets: NodeWithPos[],
inputColor: string
): string | null {
if (targets.length === 0) return null

for (const target of targets) {
const currentColor = target.node.attrs?.backgroundColor ?? null
if (currentColor !== inputColor) {
return inputColor
}
}

return null
}

export const NodeBackground = Extension.create<NodeBackgroundOptions>({
name: "nodeBackground",

addOptions() {
return {
types: [
"paragraph",
"heading",
"blockquote",
"taskList",
"bulletList",
"orderedList",
"tableCell",
"tableHeader",
],
useStyle: true,
}
},

addGlobalAttributes() {
return [
{
types: this.options.types,
attributes: {
backgroundColor: {
default: null as string | null,

parseHTML: (element: HTMLElement) => {
const styleColor = element.style?.backgroundColor
if (styleColor) return styleColor

const dataColor = element.getAttribute("data-background-color")
return dataColor || null
},

renderHTML: (attributes) => {
const color = attributes.backgroundColor as string | null
if (!color) return {}

if (this.options.useStyle) {
return {
style: `background-color: ${color}`,
}
} else {
return {
"data-background-color": color,
}
}
},
},
},
},
]
},

addCommands() {
/**
* Generic command executor for background color operations
*/
const executeBackgroundCommand = (
getTargetColor: (
targets: NodeWithPos[],
inputColor?: string
) => string | null
) => {
return (inputColor?: string) =>
({ state, tr }: { state: EditorState; tr: Transaction }) => {
const targets = getSelectedNodesOfType(
state.selection,
this.options.types
)

if (targets.length === 0) return false

const targetColor = getTargetColor(targets, inputColor)

return updateNodesAttr(tr, targets, "backgroundColor", targetColor)
}
}

return {
/**
* Set background color to specific value
*/
setNodeBackgroundColor: executeBackgroundCommand(
(_, inputColor) => inputColor || null
),

/**
* Remove background color
*/
unsetNodeBackgroundColor: executeBackgroundCommand(() => null),

/**
* Toggle background color (set if different/missing, unset if all have it)
*/
toggleNodeBackgroundColor: executeBackgroundCommand(
(targets, inputColor) => getToggleColor(targets, inputColor || "")
),
}
},
})
38 changes: 38 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/align-center-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const AlignCenterIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 6C2 5.44772 2.44772 5 3 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H3C2.44772 7 2 6.55228 2 6Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4 18C4 17.4477 4.44772 17 5 17H19C19.5523 17 20 17.4477 20 18C20 18.5523 19.5523 19 19 19H5C4.44772 19 4 18.5523 4 18Z"
fill="currentColor"
/>
</svg>
)
})

AlignCenterIcon.displayName = "AlignCenterIcon"
38 changes: 38 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/align-justify-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const AlignJustifyIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 6C2 5.44772 2.44772 5 3 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H3C2.44772 7 2 6.55228 2 6Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 12C2 11.4477 2.44772 11 3 11H21C21.5523 11 22 11.4477 22 12C22 12.5523 21.5523 13 21 13H3C2.44772 13 2 12.5523 2 12Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 18C2 17.4477 2.44772 17 3 17H21C21.5523 17 22 17.4477 22 18C22 18.5523 21.5523 19 21 19H3C2.44772 19 2 18.5523 2 18Z"
fill="currentColor"
/>
</svg>
)
})

AlignJustifyIcon.displayName = "AlignJustifyIcon"
38 changes: 38 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/align-left-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const AlignLeftIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 6C2 5.44772 2.44772 5 3 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H3C2.44772 7 2 6.55228 2 6Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 12C2 11.4477 2.44772 11 3 11H15C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13H3C2.44772 13 2 12.5523 2 12Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 18C2 17.4477 2.44772 17 3 17H17C17.5523 17 18 17.4477 18 18C18 18.5523 17.5523 19 17 19H3C2.44772 19 2 18.5523 2 18Z"
fill="currentColor"
/>
</svg>
)
})

AlignLeftIcon.displayName = "AlignLeftIcon"
38 changes: 38 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/align-right-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const AlignRightIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 6C2 5.44772 2.44772 5 3 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H3C2.44772 7 2 6.55228 2 6Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 12C8 11.4477 8.44772 11 9 11H21C21.5523 11 22 11.4477 22 12C22 12.5523 21.5523 13 21 13H9C8.44772 13 8 12.5523 8 12Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6 18C6 17.4477 6.44772 17 7 17H21C21.5523 17 22 17.4477 22 18C22 18.5523 21.5523 19 21 19H7C6.44772 19 6 18.5523 6 18Z"
fill="currentColor"
/>
</svg>
)
})

AlignRightIcon.displayName = "AlignRightIcon"
24 changes: 24 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/arrow-left-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const ArrowLeftIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M12.7071 5.70711C13.0976 5.31658 13.0976 4.68342 12.7071 4.29289C12.3166 3.90237 11.6834 3.90237 11.2929 4.29289L4.29289 11.2929C3.90237 11.6834 3.90237 12.3166 4.29289 12.7071L11.2929 19.7071C11.6834 20.0976 12.3166 20.0976 12.7071 19.7071C13.0976 19.3166 13.0976 18.6834 12.7071 18.2929L7.41421 13L19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11L7.41421 11L12.7071 5.70711Z"
fill="currentColor"
/>
</svg>
)
})

ArrowLeftIcon.displayName = "ArrowLeftIcon"
26 changes: 26 additions & 0 deletions apps/block-editor/@/components/tiptap-icons/ban-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { memo } from "react"

type SvgProps = React.ComponentPropsWithoutRef<"svg">

export const BanIcon = memo(({ className, ...props }: SvgProps) => {
return (
<svg
width="24"
height="24"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.43471 4.01458C4.34773 4.06032 4.26607 4.11977 4.19292 4.19292C4.11977 4.26607 4.06032 4.34773 4.01458 4.43471C2.14611 6.40628 1 9.0693 1 12C1 18.0751 5.92487 23 12 23C14.9306 23 17.5936 21.854 19.5651 19.9856C19.6522 19.9398 19.7339 19.8803 19.8071 19.8071C19.8803 19.7339 19.9398 19.6522 19.9856 19.5651C21.854 17.5936 23 14.9306 23 12C23 5.92487 18.0751 1 12 1C9.0693 1 6.40628 2.14611 4.43471 4.01458ZM6.38231 4.9681C7.92199 3.73647 9.87499 3 12 3C16.9706 3 21 7.02944 21 12C21 14.125 20.2635 16.078 19.0319 17.6177L6.38231 4.9681ZM17.6177 19.0319C16.078 20.2635 14.125 21 12 21C7.02944 21 3 16.9706 3 12C3 9.87499 3.73647 7.92199 4.9681 6.38231L17.6177 19.0319Z"
fill="currentColor"
/>
</svg>
)
})

BanIcon.displayName = "BanIcon"
Loading