UNPKG

@blocknote/react

Version:

A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.

611 lines (532 loc) 18.7 kB
@import url("@blocknote/core/style.css"); /* Default theme params */ .bn-root { --bn-colors-editor-text: #3f3f3f; --bn-colors-editor-background: #ffffff; --bn-colors-menu-text: #3f3f3f; --bn-colors-menu-background: #ffffff; --bn-colors-tooltip-text: #3f3f3f; --bn-colors-tooltip-background: #efefef; --bn-colors-hovered-text: #3f3f3f; --bn-colors-hovered-background: #efefef; --bn-colors-selected-text: #ffffff; --bn-colors-selected-background: #3f3f3f; --bn-colors-disabled-text: #afafaf; --bn-colors-disabled-background: #efefef; --bn-colors-shadow: #cfcfcf; --bn-colors-border: #efefef; --bn-colors-side-menu: #cfcfcf; --bn-colors-highlights-gray-text: #9b9a97; --bn-colors-highlights-gray-background: #ebeced; --bn-colors-highlights-brown-text: #64473a; --bn-colors-highlights-brown-background: #e9e5e3; --bn-colors-highlights-red-text: #e03e3e; --bn-colors-highlights-red-background: #fbe4e4; --bn-colors-highlights-orange-text: #d9730d; --bn-colors-highlights-orange-background: #f6e9d9; --bn-colors-highlights-yellow-text: #dfab01; --bn-colors-highlights-yellow-background: #fbf3db; --bn-colors-highlights-green-text: #4d6461; --bn-colors-highlights-green-background: #ddedea; --bn-colors-highlights-blue-text: #0b6e99; --bn-colors-highlights-blue-background: #ddebf1; --bn-colors-highlights-purple-text: #6940a5; --bn-colors-highlights-purple-background: #eae4f2; --bn-colors-highlights-pink-text: #ad1a72; --bn-colors-highlights-pink-background: #f4dfeb; --bn-font-family: "Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont, "Open Sans", "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; --bn-border-radius: 6px; /* Derived values */ --bn-shadow-medium: 0 4px 12px var(--bn-colors-shadow); --bn-shadow-light: 0 2px 6px var(--bn-colors-border); --bn-border: 1px solid var(--bn-colors-border); --bn-border-radius-small: max(var(--bn-border-radius) - 2px, 1px); --bn-border-radius-medium: var(--bn-border-radius); --bn-border-radius-large: max(var(--bn-border-radius) + 2px, 1px); } .bn-root[data-color-scheme="dark"] { --bn-colors-editor-text: #cfcfcf; --bn-colors-editor-background: #1f1f1f; --bn-colors-menu-text: #cfcfcf; --bn-colors-menu-background: #1f1f1f; --bn-colors-tooltip-text: #cfcfcf; --bn-colors-tooltip-background: #161616; --bn-colors-hovered-text: #cfcfcf; --bn-colors-hovered-background: #161616; --bn-colors-selected-text: #cfcfcf; --bn-colors-selected-background: #0f0f0f; --bn-colors-disabled-text: #3f3f3f; --bn-colors-disabled-background: #161616; --bn-colors-shadow: #0f0f0f; --bn-colors-border: #161616; --bn-colors-side-menu: #7f7f7f; --bn-colors-highlights-gray-text: #bebdb8; --bn-colors-highlights-gray-background: #9b9a97; --bn-colors-highlights-brown-text: #8e6552; --bn-colors-highlights-brown-background: #64473a; --bn-colors-highlights-red-text: #ec4040; --bn-colors-highlights-red-background: #be3434; --bn-colors-highlights-orange-text: #e3790d; --bn-colors-highlights-orange-background: #b7600a; --bn-colors-highlights-yellow-text: #dfab01; --bn-colors-highlights-yellow-background: #b58b00; --bn-colors-highlights-green-text: #6b8b87; --bn-colors-highlights-green-background: #4d6461; --bn-colors-highlights-blue-text: #0e87bc; --bn-colors-highlights-blue-background: #0b6e99; --bn-colors-highlights-purple-text: #8552d7; --bn-colors-highlights-purple-background: #6940a5; --bn-colors-highlights-pink-text: #da208f; --bn-colors-highlights-pink-background: #ad1a72; } .bn-root { font-family: var(--bn-font-family); } /* Editor body styling */ /* Editor styling */ .bn-editor { background-color: var(--bn-colors-editor-background); border-radius: var(--bn-border-radius-large); color: var(--bn-colors-editor-text); } /* Custom block node view wrapper styling */ .bn-react-node-view-renderer { display: flex; flex-direction: column; width: 100%; } /* Indent line styling */ .bn-block-group .bn-block:not(:has(.bn-toggle-wrapper)) .bn-block-group .bn-block-outer:not([data-prev-depth-changed])::before { border-left: 1px solid var(--bn-colors-side-menu); } /* Placeholder styling */ .bn-block-content:has(.ProseMirror-trailingBreak:only-child):after { color: var(--bn-colors-side-menu); } /* Color Icon styling */ .bn-root .bn-color-icon { align-items: center; border: var(--bn-border); border-radius: var(--bn-border-radius-small); display: flex; justify-content: center; } /* Error text styling */ .bn-error-text { color: red; font-size: 12px; } /* Highlight color styling */ [data-style-type="textColor"][data-value="gray"], [data-text-color="gray"], .bn-block:has(> .bn-block-content[data-text-color="gray"]) { color: var(--bn-colors-highlights-gray-text); } [data-style-type="textColor"][data-value="brown"], [data-text-color="brown"], .bn-block:has(> .bn-block-content[data-text-color="brown"]) { color: var(--bn-colors-highlights-brown-text); } [data-style-type="textColor"][data-value="red"], [data-text-color="red"], .bn-block:has(> .bn-block-content[data-text-color="red"]) { color: var(--bn-colors-highlights-red-text); } [data-style-type="textColor"][data-value="orange"], [data-text-color="orange"], .bn-block:has(> .bn-block-content[data-text-color="orange"]) { color: var(--bn-colors-highlights-orange-text); } [data-style-type="textColor"][data-value="yellow"], [data-text-color="yellow"], .bn-block:has(> .bn-block-content[data-text-color="yellow"]) { color: var(--bn-colors-highlights-yellow-text); } [data-style-type="textColor"][data-value="green"], [data-text-color="green"], .bn-block:has(> .bn-block-content[data-text-color="green"]) { color: var(--bn-colors-highlights-green-text); } [data-style-type="textColor"][data-value="blue"], [data-text-color="blue"], .bn-block:has(> .bn-block-content[data-text-color="blue"]) { color: var(--bn-colors-highlights-blue-text); } [data-style-type="textColor"][data-value="purple"], [data-text-color="purple"], .bn-block:has(> .bn-block-content[data-text-color="purple"]) { color: var(--bn-colors-highlights-purple-text); } [data-style-type="textColor"][data-value="pink"], [data-text-color="pink"], .bn-block:has(> .bn-block-content[data-text-color="pink"]) { color: var(--bn-colors-highlights-pink-text); } [data-style-type="backgroundColor"][data-value="gray"], [data-background-color="gray"], .bn-block:has(> .bn-block-content[data-background-color="gray"]) { background-color: var(--bn-colors-highlights-gray-background); } [data-style-type="backgroundColor"][data-value="brown"], [data-background-color="brown"], .bn-block:has(> .bn-block-content[data-background-color="brown"]) { background-color: var(--bn-colors-highlights-brown-background); } [data-style-type="backgroundColor"][data-value="red"], [data-background-color="red"], .bn-block:has(> .bn-block-content[data-background-color="red"]) { background-color: var(--bn-colors-highlights-red-background); } [data-style-type="backgroundColor"][data-value="orange"], [data-background-color="orange"], .bn-block:has(> .bn-block-content[data-background-color="orange"]) { background-color: var(--bn-colors-highlights-orange-background); } [data-style-type="backgroundColor"][data-value="yellow"], [data-background-color="yellow"], .bn-block:has(> .bn-block-content[data-background-color="yellow"]) { background-color: var(--bn-colors-highlights-yellow-background); } [data-style-type="backgroundColor"][data-value="green"], [data-background-color="green"], .bn-block:has(> .bn-block-content[data-background-color="green"]) { background-color: var(--bn-colors-highlights-green-background); } [data-style-type="backgroundColor"][data-value="blue"], [data-background-color="blue"], .bn-block:has(> .bn-block-content[data-background-color="blue"]) { background-color: var(--bn-colors-highlights-blue-background); } [data-style-type="backgroundColor"][data-value="purple"], [data-background-color="purple"], .bn-block:has(> .bn-block-content[data-background-color="purple"]) { background-color: var(--bn-colors-highlights-purple-background); } [data-style-type="backgroundColor"][data-value="pink"], [data-background-color="pink"], .bn-block:has(> .bn-block-content[data-background-color="pink"]) { background-color: var(--bn-colors-highlights-pink-background); } /* Sets base Z-index on UI elements, i.e. elements which use the `GenericPopover` component. If a z-index is passed to the `GenericPopover` via inline styles, it is added to the base z-index. */ .bn-root { --bn-ui-base-z-index: 0; } /* Matches Side Menu height to block line height. For blocks with a taller first line (e.g. headings), the menu is not stretched - instead, the SideMenuController offsets its position to keep it centered on the line. */ .bn-side-menu { height: 30px; } /* Thread sidebar styling */ .bn-threads-sidebar { border-radius: var(--bn-border-radius-medium); display: flex; flex-direction: column; gap: 10px; overflow: auto; } .bn-thread-expand-prompt .mantine-Text-root, .bn-thread .bn-header-text { color: var(--bn-colors-menu-text); } .bn-threads-sidebar .bn-thread .bn-editor { background-color: transparent; } .bn-threads-sidebar .bn-thread.selected { background-color: #f5f9fd; border: 2px solid #c2dcf8; } .dark .bn-threads-sidebar .bn-thread.selected { background-color: #20242a; border: 2px solid #23405b; } /* ---- Versioning sidebar -------------------------------------------------- * * Lives here rather than in the UI packages: every rule below was identical * across the ariakit/mantine/shadcn stylesheets, and none of it is * library-specific. Per-package overrides belong in those stylesheets, scoped * to `.bn-ariakit` / `.bn-mantine` / `.bn-shadcn` (see the Mantine * `.bn-threads-sidebar` override for the pattern). * * Resembles `.bn-threads-sidebar` above, but shares almost nothing with it * concretely: the shells have only `overflow: auto` in common (this one is a * flex *item* whose rows self-space via `margin-bottom`, not a flex column), * and the two selected states are deliberately different designs — a filled * accent with inverted text here, a pale tint with a saturated border there. * The row boxes look closer, but only against `.bn-mantine .bn-thread`: * ariakit and shadcn get their thread boxes from their own component * libraries, which BlockNote's CSS doesn't touch. A shared base class would * hold ~3 declarations and still leave every caller overriding gap, border, * radius, padding and width — so these are kept separate on purpose. */ .bn-versioning-sidebar { flex: 1; overflow: auto; padding-inline: 16px; } .bn-versioning-sidebar-header { align-items: center; display: flex; justify-content: space-between; padding-block: 16px 8px; } .bn-versioning-sidebar-header-title { align-items: center; display: flex; gap: 6px; } .bn-versioning-sidebar-title { color: var(--bn-colors-menu-text); font-size: 18px; font-weight: 700; margin: 0; } .bn-versioning-sidebar-header-actions { align-items: center; display: flex; gap: 4px; } .bn-versioning-sidebar-tabs { border-bottom: 1px solid var(--bn-colors-border); display: flex; gap: 4px; margin-bottom: 8px; } .bn-versioning-sidebar-tab { background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--bn-colors-menu-text); cursor: pointer; font-size: 13px; font-weight: 500; margin-bottom: -1px; opacity: 0.6; padding: 8px 4px; } .bn-versioning-sidebar-tab:hover { opacity: 0.85; } .bn-versioning-sidebar-tab[aria-selected="true"] { border-bottom-color: var(--bn-colors-menu-text); opacity: 1; } .bn-snapshot { background-color: var(--bn-colors-menu-background); border: 1px solid transparent; border-radius: 8px; color: var(--bn-colors-menu-text); cursor: pointer; display: flex; flex-direction: column; gap: 6px; margin-bottom: 4px; overflow: visible; padding: 12px 14px; position: relative; transition: background-color 0.12s ease, border-color 0.12s ease; width: 100%; } .bn-snapshot:hover { background-color: var(--bn-colors-hovered-background); } .bn-snapshot-name { background: transparent; border: none; color: inherit; font-size: 14px; font-weight: 700; padding: 0; width: 100%; } .bn-snapshot-name:focus { outline: none; } .bn-snapshot-body { display: flex; flex-direction: column; font-size: 13px; gap: 2px; } /* The timestamp reads as normal body text — not a muted gray. */ .bn-snapshot-date { color: var(--bn-colors-menu-text); font-size: 13px; line-height: 1.3; } /* Authors / "restored from" are secondary, but still readable. */ .bn-snapshot-original-date, .bn-snapshot-secondary-label { color: #6b7280; font-size: 13px; line-height: 1.3; } .dark .bn-snapshot-original-date, .dark .bn-snapshot-secondary-label { color: #9ca3af; } /* "..." trigger — hidden until the row is hovered or its menu is open. */ .bn-snapshot .bn-snapshot-menu { opacity: 0; position: absolute; right: 8px; top: 8px; transition: opacity 0.12s ease; } .bn-snapshot:hover .bn-snapshot-menu, .bn-snapshot:focus-within .bn-snapshot-menu { opacity: 1; } /* Strip the action-toolbar's box so the trigger is flat — just the icon. */ .bn-versioning-sidebar .bn-snapshot-menu .bn-action-toolbar { background-color: transparent; border: none; border-radius: 0; padding: 0; } .bn-versioning-sidebar .bn-snapshot .bn-snapshot-menu-trigger, .bn-versioning-sidebar .bn-snapshot .bn-snapshot-menu-trigger:hover, .bn-versioning-sidebar .bn-snapshot .bn-snapshot-menu-trigger[data-selected] { background-color: transparent; border: none; height: auto; min-width: 0; padding: 2px; } .bn-versioning-sidebar .bn-snapshot .bn-snapshot-menu-trigger:hover { opacity: 0.6; } /* Selected (currently viewed) — a distinct indigo with white text. */ .bn-versioning-sidebar .bn-snapshot.selected { background-color: #3e5de7; color: #fff; } .bn-versioning-sidebar .bn-snapshot.selected .bn-snapshot-name { color: #fff; } .bn-versioning-sidebar .bn-snapshot.selected .bn-snapshot-date, .bn-versioning-sidebar .bn-snapshot.selected .bn-snapshot-original-date, .bn-versioning-sidebar .bn-snapshot.selected .bn-snapshot-secondary-label { color: rgba(255, 255, 255, 0.8); } .bn-versioning-sidebar .bn-snapshot.selected .bn-snapshot-menu-trigger { color: #fff; } /* Comparing-to (the diff baseline) — a subtle tint of the selected indigo. */ .bn-versioning-sidebar .bn-snapshot.comparing { background-color: color-mix( in srgb, #3e5de7 8%, var(--bn-colors-editor-background) ); } .bn-snapshot-comparing-to { align-items: center; color: #3e5de7; display: flex; font-size: 13px; font-weight: 600; gap: 4px; } .bn-mobile-formatting-toolbar { display: flex; justify-content: center; position: fixed; top: 0; left: 0; width: 100vw; z-index: calc(var(--bn-ui-base-z-index) + 40); /* `translate`: Move just below bottom of visual viewport. */ /* `translateY`: Move from below under bottom edge of visual viewport to just above it. */ /* `scale`: Preserve size on zoom. */ transform: translate( var(--bn-vv-left, 0px), calc(var(--bn-vv-top, 0px) + var(--bn-vv-height, 0px)) ) translateY(-100%) scale(calc(1 / var(--bn-vv-scale, 1))); transform-origin: left bottom; will-change: transform; /* Slightly mitigates jitter. */ transition: transform 0.2s cubic-bezier(0.5, 1, 0.89, 1); padding-bottom: env(safe-area-inset-bottom, 0); } /* iOS Safari with the keyboard open answers a vertical drag on the toolbar with a viewport pan or pull-to-refresh, and the toolbar pinned to that viewport moves under the finger. On the strip, not the wrapper: WebKit reads `touch-action` only up to the nearest scroll container of the touched element, and the strip is one. */ .bn-mobile-formatting-toolbar .bn-toolbar { touch-action: pan-x; } @media (prefers-reduced-motion: reduce) { .bn-mobile-formatting-toolbar { transition: none; } } /* CSS styles for scroll container pinned to virtual viewport. Used to make the mobile formatting toolbar scroll smoother. `bn-vv-*` variables track virtual viewport and are set in `useVirtualKeyboard`. */ .bn-scroll-container { position: fixed; top: var(--bn-vv-top, 0px); left: var(--bn-vv-left, 0px); width: var(--bn-vv-width, 100vw); height: var(--bn-vv-height, 100dvh); overflow-y: auto; -webkit-overflow-scrolling: touch; /* Overscroll stays inside the container. Chained to the document it moves the page behind the pinned container, and the toolbar with it: scrolled to the end and dragging further, the whole page rubber-bands, content and toolbar jump, and a document-level scrollbar appears; at the top with the keyboard up, dragging down starts Safari's pull-to-refresh, the page slides with the finger and the toolbar drifts up from the keyboard and snaps back. */ overscroll-behavior: contain; } /* The one exception: at the top with the keyboard closed, the overscroll must reach the document or the page can no longer be refreshed by pulling. `useVirtualKeyboard` sets the attribute in exactly that state. Not with the keyboard up, where the pull moves the toolbar (see above). */ .bn-scroll-container[data-bn-allow-pull-to-refresh] { overscroll-behavior-y: auto; } /* Emoji Picker styling */ .bn-root em-emoji-picker { max-height: 100%; } /* Form.Root's <form> is a semantic wrapper, never a layout box: the skins' * containers (popover contents, the file panel's tab column) lay out the * fields and the embed tab's submit button as their own flex children, and * two skins rendered no wrapper element at all before the real <form> * arrived. `contents` keeps that geometry in every skin — verified against * each skin's containers (mantine's are block, so this is a no-op there; * ariakit/shadcn have flex+gap containers that need it). Skins must not * style .bn-form as a box. */ .bn-form { display: contents; } /* The Form.Root default submit control (`ScreenReaderOnlySubmit`): visually * hidden but NOT `display: none` - it must stay in the accessibility tree as * a labelled control, and its presence is what makes Enter submit a form * with more than one field. */ .bn-screen-reader-only-submit { border: 0; clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; white-space: nowrap; width: 1px; }