[docs] design shuffle (#2951)

This PR incorporates design tweaks from #2922 without the home page or
content changes.

These are:
- Replacing all `hello@tldraw.com` with `sales@tldraw.com`
- Fix mailto links.
- Showing the first item in a section on direct routes to the section
- Splitting the article page for human-written content from article page
for generated content
- Splitting the layout for the landing page from the rest of the site
(temporarily identical to the regular content)
- Removing headings from left sidebar
- Restoring headings in right sidebar for human-written pages with > 1
heading link
- Styling block quote
- Adjusting section link appearance / layout in header / menu
- Changing the order of search results to preference docs over examples
- Updating copy on events
- Removing copy on user interface menus
- Adding hero as prop to all articles
- Updated icon
- Fixing a few broken links
- Replaces the sandpack code blocks with hljs code blocks, except in
examples.

### Change Type

- [x] `documentation` — Changes to the documentation only[^2]
This commit is contained in:
Steve Ruiz 2024-02-29 16:28:45 +00:00 committed by GitHub
parent 3f5803729d
commit 9a6f4e8c4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 1587 additions and 1299 deletions

View file

@ -138,7 +138,7 @@ Please see our [contributing guide](https://github.com/tldraw/tldraw/blob/main/C
The tldraw source code and its distributions are provided under the [tldraw license](https://github.com/tldraw/tldraw/blob/master/LICENSE.md). This license does not permit commercial use.
If you wish to use this project in commercial product, you need to purchase a commercial license. matPlease contact us at [hello@tldraw.com](mailto:hello@tldraw.com) for more inforion about obtaining a commercial license.
If you wish to use this project in commercial product, you need to purchase a commercial license. matPlease contact us at [sales@tldraw.com](mailto:sales@tldraw.com) for more inforion about obtaining a commercial license.
## Trademarks
@ -146,4 +146,4 @@ Copyright (c) 2023-present tldraw Inc. The tldraw name and logo are trademarks o
## Contact
Find us on Twitter at [@tldraw](https://twitter.com/tldraw) or email [hello@tldraw.com](mailto://hello@tldraw.com). You can also [join our discord](https://discord.gg/rhsyWMUJxd) for quick help and support.
Find us on Twitter at [@tldraw](https://twitter.com/tldraw) or email [sales@tldraw.com](mailto://sales@tldraw.com). You can also [join our discord](https://discord.gg/rhsyWMUJxd) for quick help and support.

File diff suppressed because one or more lines are too long

View file

@ -1,12 +1,20 @@
import { ArticleDocsPage } from '@/components/ArticleDocsPage'
import { ArticleReferenceDocsPage } from '@/components/ArticleReferenceDocsPage'
import { CategoryDocsPage } from '@/components/CategoryDocsPage'
import { ExampleDocsPage } from '@/components/ExampleDocsPage'
import { SectionDocsPage } from '@/components/SectionDocsPage'
import { Article, Category, Section } from '@/types/content-types'
import { getDb } from '@/utils/ContentDatabase'
import { Metadata } from 'next'
import { notFound } from 'next/navigation'
async function getContentForPath(path: string) {
async function getContentForPath(
path: string
): Promise<
| { type: 'section'; section: Section }
| { type: 'category'; category: Category }
| { type: 'article'; article: Article }
> {
const db = await getDb()
const section = await db.db.get(`SELECT * FROM sections WHERE sections.path = ?`, path)
@ -105,6 +113,28 @@ export default async function ContentPage({ params }: { params: { id: string | s
switch (content.type) {
case 'section': {
const db = await getDb()
let firstArticleInSection: Article | undefined
const categories = await db.getCategoriesForSection(content.section.id)
for (const category of categories) {
const articles = await db.getCategoryArticles(content.section.id, category.id)
const article = articles[0]
if (article) {
firstArticleInSection = article
break
}
}
if (firstArticleInSection) {
const article = await db.getArticle(firstArticleInSection.id)
if (article?.componentCode) {
return <ExampleDocsPage article={article} />
}
return <ArticleDocsPage article={article} />
}
return <SectionDocsPage section={content.section} />
}
case 'category': {
@ -114,6 +144,11 @@ export default async function ContentPage({ params }: { params: { id: string | s
if (content.article.componentCode) {
return <ExampleDocsPage article={content.article} />
}
if (content.article.sectionId === 'reference') {
return <ArticleReferenceDocsPage article={content.article} />
}
return <ArticleDocsPage article={content.article} />
}
default: {

View file

@ -10,7 +10,7 @@ export default async function ClaPage() {
<>
<Header />
<Sidebar {...sidebar} />
<main className="article">
<main className="main-content article">
<div className="page-header">
<h1>Contributor License Agreement</h1>
</div>

View file

@ -0,0 +1,10 @@
import { Footer } from '@/components/Footer'
export default async function ContentLayout({ children }: { children: React.ReactNode }) {
return (
<div className="wrapper">
<div className="layout">{children}</div>
<Footer />
</div>
)
}

View file

@ -0,0 +1,10 @@
import { Footer } from '@/components/Footer'
export default async function ContentLayout({ children }: { children: React.ReactNode }) {
return (
<div className="wrapper">
<div className="layout">{children}</div>
<Footer />
</div>
)
}

View file

@ -1,4 +1,3 @@
import { Footer } from '@/components/Footer'
import { Analytics } from '@vercel/analytics/react'
import { Metadata, Viewport } from 'next'
import AutoRefresh from '../components/AutoRefresh'
@ -7,9 +6,9 @@ import '../styles/hljs.css'
import '../styles/parameters-table.css'
import { Providers } from './providers'
const TITLE = 'tldraw docs'
const TITLE = 'tldraw SDK'
const DESCRIPTION =
'Developer documentation for tldraw. Build infinite canvas experiences for the web.'
'Infinite canvas SDK from tldraw. Build whiteboards, design tools, and canvas experiences for the web.'
const TWITTER_HANDLE = '@tldraw'
const TWITTER_CARD = 'social-twitter.png'
const FACEBOOK_CARD = 'social-og.png'
@ -70,10 +69,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<html suppressHydrationWarning>
<body>
<Providers>
<div className="wrapper">
<div className="layout">{children}</div>
<Footer />
</div>
{children}
<Analytics />
</Providers>
</body>

View file

@ -7,15 +7,17 @@ export default async function NotFound() {
const sidebar = await db.getSidebarContentList({})
return (
<>
<div className="wrapper">
<div className="layout">
<Header />
<Sidebar {...sidebar} />
<main className="article">
<main className="main-content article">
<div className="page-header">
<h1>Not found.</h1>
</div>
<p>There's nothing here. :(</p>
</main>
</>
</div>
</div>
)
}

View file

@ -3,5 +3,5 @@
import { ThemeProvider } from 'next-themes'
export function Providers({ children }: { children: any }) {
return <ThemeProvider>{children}</ThemeProvider>
return <ThemeProvider enableSystem>{children}</ThemeProvider>
}

View file

@ -1,8 +1,8 @@
import { Article } from '@/types/content-types'
import { getDb } from '@/utils/ContentDatabase'
import { ArticleDetails } from './ArticleDetails'
import { ArticleHeadingLinks } from './ArticleHeadingLinks'
import { ArticleNavLinks } from './ArticleNavLinks'
import { Breadcrumb } from './Breadcrumb'
import { Header } from './Header'
import { Mdx } from './Mdx'
import { Sidebar } from './Sidebar'
@ -20,22 +20,20 @@ export async function ArticleDocsPage({ article }: { article: Article }) {
articleId: article.id,
})
const isGenerated = article.sectionId === 'reference'
return (
<>
<Header sectionId={section.id} />
<Sidebar headings={headings} {...sidebar} />
<main className={`article${isGenerated ? ' article__api-docs' : ''}`}>
<Sidebar {...sidebar} />
<main className="main-content article">
<div className="page-header">
<Breadcrumb section={section} category={category} />
<h1>{article.title}</h1>
</div>
{article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />}
{article.content && <Mdx content={article.content} />}
{isGenerated ? null : <ArticleDetails article={article} />}
<ArticleDetails article={article} />
{links && <ArticleNavLinks links={links} />}
</main>
<ArticleHeadingLinks article={article} headingLinks={headings} />
</>
)
}

View file

@ -0,0 +1,46 @@
/* eslint-disable no-useless-escape */
import { Article, ArticleHeading, ArticleHeadings } from '@/types/content-types'
import Link from 'next/link'
export function ArticleHeadingLinks({
headingLinks,
}: {
article: Article
headingLinks: ArticleHeadings
}) {
const linksToShow = headingLinks.filter((heading) => heading.level < 4)
if (linksToShow.length <= 1) return null
return (
<nav className="layout__headings">
<ul className="sidebar__list sidebar__sections__list">
<li className="sidebar__section">
<div className="sidebar__section__title uppercase_title">On this page</div>
<ul className="sidebar__list">
{linksToShow.map((heading) => (
<HeaderLink key={heading.slug} heading={heading} />
))}
</ul>
</li>
</ul>
</nav>
)
}
function HeaderLink({ heading }: { heading: ArticleHeading }) {
return (
<li className="sidebar__article">
<Link href={`#${heading.slug}`} className="sidebar__link">
{heading.level > 2 ? <span className="sidebar__link__indent">{''}</span> : null}
<span className="sidebar__link__title">
{heading.isCode ? (
<code>{heading.title.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1')}</code>
) : (
heading.title.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1')
)}
</span>
</Link>
</li>
)
}

View file

@ -0,0 +1,36 @@
import { Article } from '@/types/content-types'
import { getDb } from '@/utils/ContentDatabase'
import { ArticleNavLinks } from './ArticleNavLinks'
import { Breadcrumb } from './Breadcrumb'
import { Header } from './Header'
import { Mdx } from './Mdx'
import { Sidebar } from './Sidebar'
import { Image } from './mdx-components/generic'
export async function ArticleReferenceDocsPage({ article }: { article: Article }) {
const db = await getDb()
const section = await db.getSection(article.sectionId)
const category = await db.getCategory(article.categoryId)
const links = await db.getArticleLinks(article)
const sidebar = await db.getSidebarContentList({
sectionId: section.id,
categoryId: category.id,
articleId: article.id,
})
return (
<>
<Header sectionId={section.id} />
<Sidebar {...sidebar} />
<main className="main-content article article__api-docs">
<div className="page-header">
<Breadcrumb section={section} category={category} />
<h1>{article.title}</h1>
</div>
{article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />}
{article.content && <Mdx content={article.content} />}
{links && <ArticleNavLinks links={links} />}
</main>
</>
)
}

View file

@ -23,10 +23,8 @@ export async function CategoryDocsPage({ category }: { category: Category }) {
{articles.length > 0 && (
<ul>
{articles.map((article) => (
<li>
<Link key={article.id} href={`/${section.id}/${category.id}/${article.id}`}>
{article.title}
</Link>
<li key={article.id}>
<Link href={`/${section.id}/${category.id}/${article.id}`}>{article.title}</Link>
</li>
))}
</ul>

View file

@ -1,18 +1,15 @@
import { Article } from '@/types/content-types'
import { getDb } from '@/utils/ContentDatabase'
import { ArticleNavLinks } from './ArticleNavLinks'
import { Breadcrumb } from './Breadcrumb'
import ExampleCodeBlock from './ExampleCodeBlock'
import { Header } from './Header'
import { Mdx } from './Mdx'
import { Sidebar } from './Sidebar'
import { Image } from './mdx-components/generic'
export async function ExampleDocsPage({ article }: { article: Article }) {
const db = await getDb()
const section = await db.getSection(article.sectionId)
const category = await db.getCategory(article.categoryId)
const headings = await db.getArticleHeadings(article.id)
const links = await db.getArticleLinks(article)
const sidebar = await db.getSidebarContentList({
sectionId: section.id,
@ -23,16 +20,13 @@ export async function ExampleDocsPage({ article }: { article: Article }) {
return (
<>
<Header sectionId={section.id} />
<Sidebar headings={headings} {...sidebar} />
<main className={`article article__example`}>
<Sidebar {...sidebar} />
<main className={`main-content article article__example`}>
<div className="page-header">
<Breadcrumb section={section} category={category} />
<h1>{article.title}</h1>
{article.description && <p>{article.description}</p>}
</div>
{article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />}
{article.content && <Mdx content={article.content} />}
{article.componentCode && (
<ExampleCodeBlock
articleId={article.id}
files={{
@ -41,7 +35,6 @@ export async function ExampleDocsPage({ article }: { article: Article }) {
}}
activeFile={'App.tsx'}
/>
)}
{links && <ArticleNavLinks links={links} />}
</main>
</>

View file

@ -1,44 +1,43 @@
'use client'
import { debounce } from '@/utils/debounce'
import { useEffect, useRef, useState } from 'react'
import { useRef } from 'react'
export default function FancyBox() {
const rContainer = useRef<HTMLDivElement>(null)
const [items, setItems] = useState<number[]>([])
// const [items, setItems] = useState<number[]>([])
useEffect(() => {
const populate = debounce(() => {
const elm = rContainer.current
if (!elm) return
// useEffect(() => {
// const populate = debounce(() => {
// const elm = rContainer.current
// if (!elm) return
const width = elm.clientWidth
const height = elm.clientHeight
// const width = elm.clientWidth
// const height = elm.clientHeight
const SIZE = 32
// const SIZE = 32
const cols = Math.ceil(width / SIZE)
const rows = Math.ceil(height / SIZE)
// const cols = Math.ceil(width / SIZE)
// const rows = Math.ceil(height / SIZE)
const items = Array.from(Array(cols * rows)).map((_, i) => i)
// const items = Array.from(Array(cols * rows)).map((_, i) => i)
setItems(items)
}, 100)
// setItems(items)
// }, 100)
populate()
// populate()
window.addEventListener('resize', populate)
return () => {
window.removeEventListener('resize', populate)
}
}, [])
// window.addEventListener('resize', populate)
// return () => {
// window.removeEventListener('resize', populate)
// }
// }, [])
return (
<div className="footer__fancybox" ref={rContainer}>
{items.map((i) => {
{/* {items.map((i) => {
const c = 1 + (i % 7)
return <div key={i} className="footer__fancybox__item" data-c={c} />
})}
})} */}
</div>
)
}

View file

@ -18,11 +18,7 @@ export function Footer() {
<p>tldraw © {new Date().getFullYear()}</p>
</a>
<div className="footer__socials">
<a
href="https://twitter.com/tldraw"
className="sidebar__button icon-button"
title="twitter"
>
<a href="https://x.com/tldraw" className="sidebar__button icon-button" title="x">
<Icon icon="twitter" />
</a>
<a

View file

@ -10,18 +10,16 @@ export function Header({ sectionId }: { sectionId?: string }) {
<div className="layout__header">
<div className="layout__header__left">
<Link href="/quick-start">
<div
className="lockup"
style={{
mask: `url(/lockup.svg) center 100% / 100% no-repeat`,
WebkitMask: `url(/lockup.svg) center 100% / 100% no-repeat`,
}}
/>
<img className="logo-dark" src="/tldraw_dev_dark.png" />
<img className="logo-light" src="/tldraw_dev_light.png" />
</Link>
</div>
<Search />
<div className="layout__header__sections_and_socials">
<div className="layout__header__links">
<div className="layout__header__sections">
<SectionLinks sectionId={sectionId} />
</div>
<div className="layout__header__socials">
<a
href="https://x.com/tldraw/"
className="sidebar__button icon-button"
@ -49,6 +47,7 @@ export function Header({ sectionId }: { sectionId?: string }) {
<ThemeSwitcher />
</div>
</div>
</div>
)
}

View file

@ -13,7 +13,7 @@ export function Chevron({ className }: { className?: string }) {
<path
d="M4 6L8 10L12 6"
stroke="currentColor"
strokeWidth="2"
strokeWidth="1"
strokeLinecap="round"
strokeLinejoin="round"
/>

View file

@ -1,8 +1,8 @@
import { MDXRemote } from 'next-mdx-remote/rsc'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeHighlight from 'rehype-highlight'
import rehypeSlug from 'rehype-slug-custom-id'
import { components } from './mdx-components'
// import rehypeHighlight from 'rehype-highlight'
interface MdxProps {
content: string
@ -17,7 +17,7 @@ export function Mdx({ content }: MdxProps) {
mdxOptions: {
// remarkPlugins: [remarkGfm, {}],
rehypePlugins: [
// [rehypeHighlight as any, {}],
[rehypeHighlight as any, {}],
[rehypeAutolinkHeadings, {}],
[rehypeSlug, { enableCustomId: true, maintainCase: true, removeAccents: true }],
],

View file

@ -102,7 +102,7 @@ export function Search() {
// {searchType === SEARCH_TYPE.NORMAL ? '✨ Search using AI' : '⭐ Search without AI'}
// </button>
// }
groups={['examples', 'docs', 'reference']}
groups={['docs', 'examples', 'reference']}
groupsToLabel={{ examples: 'Examples', docs: 'Articles', reference: 'Reference' }}
options={searchResults}
isLoading={isLoading}

View file

@ -11,7 +11,7 @@ export async function SectionDocsPage({ section }: { section: Section }) {
<>
<Header sectionId={section.id} />
<Sidebar {...sidebar} />
<main className="article">
<main className="main-content article">
<div className="page-header">
<h1>{section.title}</h1>
</div>

View file

@ -33,7 +33,7 @@ const linkContext = createContext<{
// it keeps re-rendering.
let scrollPosition = 0
export function Sidebar({ headings, links, sectionId, categoryId, articleId }: SidebarProps) {
export function Sidebar({ links, sectionId, categoryId, articleId }: SidebarProps) {
const activeId = articleId ?? categoryId ?? sectionId
const sidebarRef = useRef<HTMLDivElement>(null)
@ -72,7 +72,7 @@ export function Sidebar({ headings, links, sectionId, categoryId, articleId }: S
<div className="sidebar__section__links">
<SectionLinks sectionId={sectionId} />
</div>
<SidebarLinks headings={headings} links={links} />
<SidebarLinks links={links} />
<SidebarCloseButton />
</div>
<ToggleMenuButton />
@ -81,62 +81,48 @@ export function Sidebar({ headings, links, sectionId, categoryId, articleId }: S
)
}
export function SidebarLinks({
headings,
links,
}: {
headings?: ArticleHeadings
links: SidebarContentLink[]
}) {
export function SidebarLinks({ links }: { links: SidebarContentLink[] }) {
return (
<nav className="sidebar__nav">
<ul className="sidebar__list sidebar__sections__list">
{links.map((link) => (
<SidebarLink key={link.url} headings={headings} {...link} />
<SidebarLink key={link.url} {...link} />
))}
</ul>
</nav>
)
}
function SidebarLink({ headings, ...props }: SidebarContentLink & { headings?: ArticleHeadings }) {
function SidebarLink(props: SidebarContentLink) {
switch (props.type) {
case 'section': {
return <SidebarSection headings={headings} {...props} />
return <SidebarSection {...props} />
}
case 'article': {
return <SidebarArticle headings={headings} {...props} />
return <SidebarArticle {...props} />
}
case 'category': {
return <SidebarCategory headings={headings} {...props} />
return <SidebarCategory {...props} />
}
}
}
function SidebarSection({
title,
children,
headings,
}: SidebarContentSectionLink & { headings?: ArticleHeadings }) {
function SidebarSection({ title, children }: SidebarContentSectionLink) {
if (children.length === 0) return null
return (
<li className="sidebar__section">
{title && <span className="sidebar__section__title">{title}</span>}
{title && <span className="sidebar__section__title uppercase_title">{title}</span>}
<ul className="sidebar__list">
{children.map((link) => (
<SidebarLink key={link.url} headings={headings} {...link} />
<SidebarLink key={link.url} {...link} />
))}
</ul>
</li>
)
}
function SidebarCategory({
title,
children,
headings,
}: SidebarContentCategoryLink & { headings?: ArticleHeadings }) {
function SidebarCategory({ title, children }: SidebarContentCategoryLink) {
const linkCtx = useContext(linkContext)
if (children.length === 0) return null
const hasGroups = children.some((child) => !!(child as SidebarContentArticleLink).groupId)
@ -171,7 +157,7 @@ function SidebarCategory({
<Accordion.Content>
<ul className="sidebar__list sidebar__group">
{articles.map((link) => (
<SidebarLink key={link.url} headings={headings} {...link} />
<SidebarLink key={link.url} {...link} />
))}
</ul>
</Accordion.Content>

View file

@ -5,12 +5,7 @@ import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
export const Code = (props: any) => {
if (!props.className) {
return <code {...props} />
}
const language = props.className.replace('language-', '')
return <CodeBlock code={{ [`App.${language}`]: props.children.trim() }} />
}
export function CodeBlock({ code }: { code: SandpackFiles }) {

View file

@ -150,7 +150,7 @@ export const Footnotes = (props: any) => {
/* -------------------- API docs -------------------- */
export const ApiHeading = (props: any) => {
return <div {...props} />
return <div className="article__api-heading uppercase_title" {...props} />
}
export const Embed = (props: any) => {
@ -161,3 +161,14 @@ export const Embed = (props: any) => {
</div>
)
}
/* -------------------- Callouts -------------------- */
export const Callout = ({ icon, children }: any) => {
return (
<div className="article__callout">
<span>{icon}</span>
<p>{children}</p>
</div>
)
}

View file

@ -4,6 +4,7 @@ import {
A,
ApiHeading,
Blockquote,
Callout,
Divider,
Embed,
Heading1,
@ -56,6 +57,7 @@ export const components = {
Image,
Small: Small,
Video,
Callout,
...customComponents,
...apiComponents,
}

View file

@ -9,14 +9,14 @@
{
"id": "tldraw",
"name": "tldraw",
"email": "hello@tldraw.com",
"email": "sales@tldraw.com",
"twitter": "tldraw",
"image": "tldraw.jpg"
},
{
"id": "api",
"name": "API",
"email": "hello@tldraw.com",
"email": "sales@tldraw.com",
"twitter": "tldraw",
"image": "api.jpg"
}

View file

@ -10,7 +10,7 @@ tldraw uses a dual licensing model to support the development of the project.
The project's source code, libraries, and distributions are provided under the [tldraw licence](https://github.com/tldraw/tldraw/blob/master/LICENSE.md).
This license does not permit commercial use. If you wish to use this project in commercial product or enterprise, you need to purchase a commercial license.
This license does not permit commercial use. If you wish to use this project in a commercial product or enterprise, you need to purchase a commercial license.
To purchase a commercial license, or for more information, please contact us at [sales@tldraw.com](mailto:sales@tldraw.com).

View file

@ -1,5 +1,5 @@
---
title: User Interface
title: User interface
status: published
author: steveruizok
date: 3/22/2023
@ -39,6 +39,27 @@ All of our user interface works by controlling the editor via its `Editor` metho
The source for these examples are available in the [tldraw repository](https://github.com/tldraw/tldraw/blob/main/apps/examples/src) or in a [sandbox here](https://stackblitz.com/github/tldraw/tldraw/tree/examples?file=src%2Findex.tsx).
## Events
The [Tldraw](?) component has a prop, `onUiEvent`, that the user interface will call when certain events occur.
```tsx
function Example() {
function handleEvent(name, data) {
// do something with the event
}
return <Tldraw onUiEvent={handleEvent} />
}
```
The `onUiEvent` callback is called with the name of the event as a string and an object with information about the event's source (e.g. `menu` or `context-menu`) and possibly other data specific to each event, such as the direction in an `align-shapes` event.
Note that `onUiEvent` is only called when interacting with the user interface. It is not called when running commands manually against the app, e.g. calling [Editor#alignShapes](?) will not call `onUiEvent`.
See the [tldraw repository](https://github.com/tldraw/tldraw/tree/main/apps/examples) for an example of how to customize tldraw's user interface.
## Overrides
The content of tldraw's menus can be controlled via the `overrides` prop. This prop accepts a [TLUiOverrides](/reference/tldraw/TLUiOverrides) object, which has methods for each part of the user interface, such as the `toolbar` or `keyboardShortcutsMenu`.
@ -99,70 +120,6 @@ const myOverrides: TLUiOverrides = {
The `tools` object is a map of [TLUiToolItem](/reference/tldraw/TLUiToolItem)s, with each item keyed under its `id`.
### Toolbar and Menus
The remaining overrides are for toolbar and the various menus: the main menu, actions menu, context menu, help menu, and the keyboard shortcuts menu.
Each of these overrides accepts a method that receives the default menu schema and returns a mutated version of that schema.
```ts
const myOverrides: TLUiOverrides = {
actions(editor, actions) {
// Create a new action or replace an existing one
actions['my-new-action'] = {
id: 'my-new-action',
label: 'My new action',
readonlyOk: true,
kbd: '$u',
onSelect(source: any) {
window.alert('My new action just happened!')
},
}
return actions
},
contextMenu(editor, contextMenu, { actions }) {
const newMenuItem = menuItem(actions['my-new-action'])
const newMenuGroup = menuGroup('my-items', newMenuItem)
contextMenu.unshift(newMenuItem)
return contextMenu
},
menu(editor, menu, { actions }) {
// using the findMenuItem helper
const fileMenu = findMenuItem(menu, ['menu', 'file'])
if (fileMenu.type === 'submenu') {
// add the new item to the file menu's children
const newMenuItem = menuItem(actions['my-new-action'])
fileMenu.children.unshift(newMenuItem)
}
return menu
},
}
```
A menu schema is an array of either [submenus](/reference/tldraw/TLUiSubMenu), [groups](/reference/tldraw/TLUiMenuGroup), [items](/reference/tldraw/TLUiMenuItem), or [custom items](/reference/tldraw/TLUiCustomMenuItem). Each group or submenu may include any of the other types as its children.
The menu schema is stateful. Referencing atomic properties (such as computed values in the editor) will cause the menu to update when those values change. If you wish for a menu item to disappear from the menu, you can return `null` from the menu method. You can also provide additional options for each item, `disabled` or `checked`.
```ts
const myOverrides: TLUiOverrides = {
menu(editor, menu, { actions }) {
const selectedShapes = editor.getSelectedShapeIds().length
const newMenuGroup = menuGroup(
'my-actions',
selectedShapes > 0 ? menuItem(actions['action-a']) : null,
menuItem(actions['action-b'], { disabled: selectedShapes < 3 })
)
menu.unshift(newMenuGroup)
return menu
},
}
```
It's recommmended to explore the [default menu schema](https://github.com/tldraw/tldraw/blob/main/packages/tldraw/src/lib/ui/hooks/useMenuSchema.tsx) in order to understand how menu items work.
### Translations
The `translations` method accepts a table of new translations. For example, if you wanted a tool to reference a key `"tools.card"`, then you should at minimum provide an english translation for this key.
@ -176,23 +133,3 @@ const myOverrides: TLUiOverrides = {
},
}
```
## Events
The [Tldraw](?) component has a prop, `onUiEvent`, that the user interface will call when certain events occur.
```tsx
function Example() {
function handleEvent(name, data) {
// do something with the event
}
return <Tldraw onUiEvent={handleEvent} />
}
```
The `onUiEvent` callback is called with the name of the event as a string and an object with information about the event's source (e.g. `menu` or `context-menu`) and possibly other data specific to each event, such as the direction in an `align-shapes` event.
Note that `onUiEvent` is only called when interacting with the user interface. It is not called when running commands manually against the app, e.g. calling [Editor#alignShapes](?) will not call `onUiEvent`.
See the [tldraw repository](https://github.com/tldraw/tldraw/tree/main/apps/examples) for an example of how to customize tldraw's user interface.

View file

@ -12,71 +12,64 @@ The tldraw SDK provides a really simple way to craft infinite canvas experiences
By the end of this guide you will have made something that looks like this:
<Embed className="article__embed--quickstart" src="https://vite-template-five.vercel.app/" />
<Embed className="article__embed--quickstart" src="https://examples.tldraw.com/develop" />
### 1. Installation
<hr />
<ol className="ordered-list__quickstart">
<li>
### Installation
- Set up a React project however you normally do. [We recommend Vite](https://vitejs.dev/guide/#scaffolding-your-first-vite-project).
- Install the tldraw library using this command:
- Set up a React project however you normally do. [We recommend Vite](https://vitejs.dev/guide/#scaffolding-your-first-vite-project).
- Install the tldraw library using this command:
```bash
npm install @tldraw/tldraw@beta
```
```bash
npm install tldraw@beta
```
</li>
<li>
### Import Styles
<br />
To import fonts and CSS for tldraw:
### 2. Import Styles
- Create or edit a css file called `index.css`
- Copy and paste this into the file:
```CSS
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&family=Roboto+Mono:wght@400;700&display=swap");
@import url("tldraw/tldraw.css");
To import fonts and CSS for tldraw:
body {
- Create or edit a css file called `index.css`
- Copy and paste this into the file:
```CSS
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@500;700;&display=swap");
@import url("@tldraw/tldraw/tldraw.css");
body {
font-family: "Inter";
}
```
</li>
<li>
### Render Tldraw Component
<br />
To render the Tldraw component
}
```
- Import the `<Tldraw />` component from `tldraw`
- Import the `index.css` CSS file from earlier
- Wrap the Tldraw component in a `<div>` element with the style attribute set to: `{ position: 'fixed', inset: 0 }`
### 3. Render Tldraw Component
<p className="">This will render a full screen canvas:</p>
To render the Tldraw component
```javascript
import { Tldraw } from "tldraw";
import "./index.css";
- Import the `<Tldraw />` component from `@tldraw/tldraw`
- Import the `index.css` CSS file from earlier
- Wrap the Tldraw component in a `<div>` element with the style attribute set to: `{ position: 'fixed', inset: 0 }`
export default function App() {
This will render a full screen canvas:
```javascript
import { Tldraw } from "@tldraw/tldraw";
import "./index.css";
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw />
</div>
);
}
```
</li>
</ol>
}
```
<hr />
## Next Steps
### Next Steps
Now that you have your canvas working, you may be wondering: what next?
You did it! Now that you have your canvas working, you may be wondering: what next? You can try:
You can try:
- Giving the editor a makeover by [customizing the UI](/docs/user-interface)
- Adding your own [shapes](/docs/shapes) and [tools](/docs/tools)
- Providing collaboration using [multiplayer](https://github.com/tldraw/tldraw-yjs-example)
We provide the above examples and more in our [examples section](/examples/basic/develop). Go build something creative and please do share it with us in our [#show-and-tell](https://discord.com/invite/SBBEVCA4PG) channel on Discord!
We provide the above examples and more in our [examples section](/examples). Go build something creative and please do share it with us in our [#show-and-tell](https://discord.com/invite/SBBEVCA4PG) channel on Discord!

View file

@ -9,7 +9,7 @@
{
"id": "docs",
"title": "Learn tldraw",
"description": "Developer documentation for tldraw.",
"description": "Learn to use the tldraw SDK.",
"categories": [],
"sidebar_behavior": "show-links"
},
@ -58,7 +58,8 @@
"id": "Namespace",
"path": null
}
]
],
"hero": null
},
{
"id": "store",
@ -93,7 +94,8 @@
"id": "Namespace",
"path": null
}
]
],
"hero": null
},
{
"id": "tldraw",
@ -128,7 +130,8 @@
"id": "Namespace",
"path": null
}
]
],
"hero": null
},
{
"id": "tlschema",
@ -163,7 +166,8 @@
"id": "Namespace",
"path": null
}
]
],
"hero": null
},
{
"id": "validate",
@ -198,9 +202,11 @@
"id": "Namespace",
"path": null
}
]
],
"hero": null
}
],
"sidebar_behavior": "reference"
"sidebar_behavior": "reference",
"hero": null
}
]

View file

@ -29,7 +29,7 @@
"dev": "concurrently \"NODE_ENV=development next dev --port=3001\" \"tsx ./watcher.ts\" --kill-others",
"next-dev": "next dev",
"lint": "yarn run -T tsx ../../scripts/lint.ts",
"build": "yarn create-api-markdown && yarn refresh-content && next build",
"build": "yarn create-api-markdown && yarn refresh-content && next build && yarn check-links",
"start": "yarn create-api-markdown && yarn refresh-content && next start",
"fetch-api-source": "yarn run -T tsx --tsconfig ./tsconfig.content.json ./scripts/fetch-api-source.ts",
"fetch-releases": "yarn run -T tsx --tsconfig ./tsconfig.content.json ./scripts/fetch-releases.ts",
@ -54,7 +54,6 @@
"@types/sqlite3": "^3.1.9",
"@types/ws": "^8.5.9",
"@vercel/analytics": "^1.1.1",
"broken-link-checker": "^0.7.8",
"classnames": "^2.3.2",
"concurrently": "^8.2.2",
"dotenv": "^16.3.1",
@ -87,5 +86,8 @@
"unist-util-visit": "^5.0.0",
"vectra": "^0.4.4",
"ws": "^8.16.0"
},
"devDependencies": {
"linkinator": "^6.0.4"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -1,29 +1,25 @@
import { nicelog } from '@/utils/nicelog'
import blc from 'broken-link-checker'
const IGNORED_URLS = ['https://twitter.com/tldraw', 'https://tldraw.com']
import { check } from 'linkinator'
export async function checkBrokenLinks() {
nicelog('Checking broken links...')
const checked = new Set<string>()
const checker = new blc.SiteChecker(
{
filterLevel: 1,
},
{
link(result) {
if (IGNORED_URLS.includes(result.url.original)) return
if (checked.has(result.url.resolved)) return
// nicelog('Checking', result.url.resolved.replace('http://localhost:3001', ''))
if (result.broken) {
nicelog(`BROKEN: ${result.url.resolved} on page ${result.base.resolved}`)
}
checked.add(result.url.resolved)
},
end() {
nicelog('done')
},
}
const results = await check({
path: 'http://localhost:3001',
recurse: true,
})
// All good
if (results.passed) return
// There seems to be a porblem
nicelog(
`𐄂 Broken links detected!\n\n` +
results.links
.filter((result) => result.state !== 'OK')
.map(
(result, i) =>
`${i + 1}.\t${result.url}\n\tFrom: ${result.parent}\n\tStatus: ${result.status}`
)
.join('\n\n') +
'\n\n'
)
checker.enqueue('http://localhost:3001/docs/assets', null)
}

View file

@ -13,6 +13,7 @@ export async function createApiMarkdown() {
description: "Reference for the tldraw package's APIs (generated).",
categories: [],
sidebar_behavior: 'reference',
hero: null,
}
const addedCategories = new Set<string>()
@ -55,6 +56,7 @@ export async function createApiMarkdown() {
id: title,
path: null,
})),
hero: null,
})
addedCategories.add(categoryName)
}

View file

@ -8,13 +8,14 @@ const section: InputSection = {
title: 'Examples',
description: 'Code recipes for bending tldraw to your will.',
categories: [
{ id: 'basic', title: 'Getting Started', description: '', groups: [] },
{ id: 'ui', title: 'UI & Theming', description: '', groups: [] },
{ id: 'shapes/tools', title: 'Shapes & Tools', description: '', groups: [] },
{ id: 'data/assets', title: 'Data & Assets', description: '', groups: [] },
{ id: 'editor-api', title: 'Editor API', description: '', groups: [] },
{ id: 'collaboration', title: 'Collaboration', description: '', groups: [] },
{ id: 'basic', title: 'Getting Started', description: '', groups: [], hero: null },
{ id: 'ui', title: 'UI & Theming', description: '', groups: [], hero: null },
{ id: 'shapes/tools', title: 'Shapes & Tools', description: '', groups: [], hero: null },
{ id: 'data/assets', title: 'Data & Assets', description: '', groups: [], hero: null },
{ id: 'editor-api', title: 'Editor API', description: '', groups: [], hero: null },
{ id: 'collaboration', title: 'Collaboration', description: '', groups: [], hero: null },
],
hero: null,
sidebar_behavior: 'show-links',
}

View file

@ -166,6 +166,7 @@ export function generateSection(section: InputSection, articles: Articles, index
groups: [],
path: `/${section.id}/ucg`,
content: null,
hero: null,
},
]
@ -188,6 +189,7 @@ export function generateSection(section: InputSection, articles: Articles, index
index: i + 1,
path: `/${section.id}/${inputCategory.id}`,
content: null,
hero: null,
groups: inputCategory.groups.map(({ id }, i) => ({
id,
title: id,
@ -210,6 +212,7 @@ export function generateSection(section: InputSection, articles: Articles, index
index,
categories,
content: '',
hero: section.hero ?? null,
path: `/${section.id}`,
}
}

View file

@ -217,7 +217,7 @@ async function addDocComment(result: Result, member: ApiItem) {
if (exampleBlocks.length) {
result.markdown += `\n\n`
result.markdown += `##### Example\n\n`
result.markdown += `<ApiHeading>Example</ApiHeading>\n\n`
for (const example of exampleBlocks) {
result.markdown += await MarkdownWriter.docNodeToMarkdown(member, example.content)
}
@ -393,7 +393,7 @@ function addTags(result: Result, member: ApiItem) {
tags.push('readonly')
}
tags.push(member.kind.toLowerCase())
result.markdown += `<Small>${tags.join(' ')}</Small>\n\n`
result.markdown += `<Small>${tags.filter((t) => t.toLowerCase() !== 'none').join(' ')}</Small>\n\n`
}
function addReferences(result: Result, member: ApiItem) {

View file

@ -19,13 +19,15 @@
--color-tint-5: rgb(144, 144, 144);
--color-tint-6: rgb(81, 81, 81);
--color-blockquote: rgb(242, 247, 255);
/* Light theme */
--color-text: #1d1d1d;
--color-text-secondary: #666;
--color-background: #ffffff;
--color-contrast: #ffffff;
--color-accent: #2f80ed;
--color-footer-background: #212529;
--color-footer-background: hsl(240, 5%, 8%);
--color-footer-text: #fafafa;
--shadow-small: 0px 0px 16px -2px rgba(0, 0, 0, 0.12), 0px 0px 4px 0px rgba(0, 0, 0, 0.12);
@ -47,7 +49,8 @@
--border-radius-menu: 4px;
/* Sizes */
--header-height: 72px;
--header-height: 80px;
--header-padding: 24px;
}
[data-theme='dark'] {
@ -57,7 +60,7 @@
--color-background: hsl(240, 5%, 8%);
--color-contrast: #000;
--color-accent: #74b0ff;
--color-footer-background: #0d0d0d;
--color-footer-background: hsl(240, 5%, 8%);
--color-footer-text: #ccc;
--shadow-small: 0px 0px 16px -2px rgba(0, 0, 0, 0.52), 0px 0px 4px 0px rgba(0, 0, 0, 0.62);
@ -71,6 +74,8 @@
--color-tint-5: rgb(144, 144, 144);
--color-tint-6: rgb(186, 186, 186);
--color-blockquote: rgb(34, 47, 55);
/* Code colors */
--hl: #c8c5f1;
--hl-0: #5c6370;
@ -93,7 +98,7 @@
html {
background-color: #000;
border-bottom: none;
scroll-padding-top: var(--header-height);
scroll-padding-top: calc(var(--header-height) + var(--header-padding));
}
body {
@ -137,7 +142,7 @@ body {
z-index: 900;
top: 0px;
display: grid;
padding: 16px;
padding: 0px 16px;
grid-template-columns: 250px 1fr auto;
gap: 16px;
justify-content: center;
@ -145,24 +150,31 @@ body {
color: var(--color-text);
}
.layout__header .lockup {
position: relative;
width: calc(71px * (30 / 18));
height: calc(18px * (30 / 18));
background: currentColor;
color: var(--color-text);
margin-bottom: 8px;
.layout__header__left img {
width: calc(136px);
height: auto;
}
.layout__header__sections_and_socials {
.layout__header__links {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.layout__header__sections {
display: flex;
align-items: center;
}
.layout__header__socials {
display: flex;
align-items: center;
}
.layout_header__section {
text-decoration: none;
padding: 8px 12px;
padding: 13px 12px;
font-size: 14px;
color: var(--color-text);
position: relative;
@ -172,7 +184,7 @@ body {
position: absolute;
display: block;
content: '';
inset: 7px 1px;
inset: 7px 2px;
background-color: var(--bg);
border-radius: var(--border-radius-menu);
}
@ -241,11 +253,11 @@ body {
background-color: currentColor;
}
.article {
.main-content {
justify-self: center;
width: 100%;
min-height: calc(100vh - 64px);
padding: 0px 0px 96px 0px;
padding: var(--header-padding) 0px 96px 0px;
font-weight: 400;
overflow-x: hidden;
overflow-y: visible;
@ -354,7 +366,7 @@ body {
}
.article > h2 {
margin-top: 16px;
margin-top: 48px;
}
.article > p + h2 {
@ -468,9 +480,10 @@ body {
.article > blockquote {
max-width: 100%;
margin: 20px 0px;
padding-left: 16px;
border-left: 2px solid var(--color-tint-2);
margin: 32px 0px;
padding: 16px;
border-radius: var(--border-radius-menu);
background-color: var(--color-blockquote);
}
.article pre {
@ -517,8 +530,7 @@ body {
color: var(--color-text);
}
.article ol h3,
.article ol li::marker {
.article ol h3 {
font-size: 1.17em;
line-height: 28px;
}
@ -551,7 +563,6 @@ body {
.page-header > p {
margin-top: 1rem;
}
.article table {
@ -624,6 +635,7 @@ body {
.article__embed--quickstart {
aspect-ratio: 16 / 9;
min-height: 405px;
margin: 32px 0px;
}
@media screen and (max-width: 520px) {
@ -649,8 +661,8 @@ body {
.breadcrumb {
font-size: 14px;
color: var(--color-text);
font-weight: 600;
height: 40px;
font-weight: 500;
padding-bottom: 4px;
display: flex;
align-items: center;
gap: 4px;
@ -675,7 +687,6 @@ body {
font-size: 12px;
gap: 24px;
color: var(--color-footer-text);
border-top: 1px solid rgba(144, 144, 144, 0.28);
overflow: hidden;
}
@ -781,7 +792,7 @@ body {
align-self: start;
top: var(--header-height);
margin-left: -12px;
padding: 24px 28px 120px 12px;
padding: var(--header-padding) 28px 120px 12px;
max-height: calc(100vh);
width: 290px;
z-index: 800;
@ -815,7 +826,7 @@ body {
align-self: start;
top: var(--header-height);
margin-left: -12px;
padding: 0px 12px 120px 28px;
padding: var(--header-padding) 12px 120px 28px;
width: calc(100% + 24px);
max-height: calc(100vh);
z-index: 800;
@ -934,18 +945,21 @@ body {
transition-delay: 0s;
}
.sidebar__section__title {
.uppercase_title {
text-transform: uppercase;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
}
.sidebar__section__title {
margin-bottom: 4px;
position: relative;
letter-spacing: 0.5px;
height: 40px;
padding-bottom: 4px;
display: flex;
align-items: center;
justify-content: flex-start;
color: var(--color-text-secondary);
text-transform: uppercase;
--bg: transparent;
white-space: nowrap;
}
@ -958,7 +972,6 @@ body {
display: flex;
align-items: center;
justify-content: space-between;
color: var(--color-text-secondary);
white-space: nowrap;
background: transparent;
border: 0;
@ -971,7 +984,6 @@ body {
.sidebar__sections__list > *:nth-last-of-type(n + 2) > .sidebar__list {
padding-bottom: 12px;
margin-bottom: 12px;
border-bottom: 1px solid var(--color-tint-2);
}
@media (hover: hover) {
@ -1113,8 +1125,7 @@ body {
grid-gap: 40px;
}
.layout__header .layout__header__sections_and_socials .layout_header__section,
.layout__header .layout__header__sections_and_socials .NavigationMenuRoot {
.layout__header .NavigationMenuRoot {
display: none;
}
@ -1122,10 +1133,10 @@ body {
position: relative;
z-index: 1;
display: flex;
justify-content: space-around;
padding: 16px 0;
border-top: 1px solid var(--color-accent);
border-bottom: 1px solid var(--color-accent);
padding: 12px 0px;
border-bottom: 1px solid var(--color-tint-2);
margin-bottom: 12px;
margin-left: -8px;
}
.NavigationMenuTrigger {
@ -1142,7 +1153,7 @@ body {
}
.layout__header {
grid-template-columns: auto auto;
grid-template-columns: auto 1fr;
justify-content: space-between;
}
@ -1227,7 +1238,7 @@ body {
display: none;
}
.article {
.main-content {
padding: 24px 16px 16px 16px;
}
@ -1288,6 +1299,14 @@ body {
display: none;
}
.layout__header__links {
justify-content: flex-end;
}
.layout__header__sections {
display: none;
}
.article__links__prev {
border: none;
grid-row: 2;
@ -1327,6 +1346,7 @@ html[data-theme='light'] .hero__dark {
}
.code-example .sandpack {
margin-top: 20px;
margin-bottom: 32px;
}
@ -1358,12 +1378,12 @@ html[data-theme='light'] .hero__dark {
/* ------------------- Hero images ------------------ */
.hero__images {
margin: 32px 0px;
.hero__images__wrapper {
padding-bottom: 24px;
}
.hero_images > a {
margin: 0px;
.hero__images {
margin: 32px 0px;
}
.article__image {
@ -1496,3 +1516,83 @@ html[data-theme='light'] .hero__dark {
.scroll-light::-webkit-scrollbar-thumb:hover {
background-color: rgba(144, 144, 144);
}
/* ------------------ Landing page ------------------ */
.landing {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.landing__inner {
width: fit-content;
max-width: 960px;
height: fit-content;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.landing__logo {
display: flex;
align-items: center;
justify-content: center;
}
.landing__logo img {
width: 200px;
height: auto;
}
[data-theme='dark'] .logo-light {
display: none;
}
[data-theme='light'] .logo-dark {
display: none;
}
.landing__blurb {
font-size: 1em;
font-weight: 500;
text-align: center;
margin: 12px 0 16px 0;
}
.landing__links {
list-style-type: none;
display: flex;
gap: 0px;
}
.landing__links a {
text-decoration: none;
color: var(--color-text);
padding: 16px 16px;
position: relative;
font-size: inherit;
font-family: inherit;
font-weight: 600;
}
.landing__links a::after {
position: absolute;
display: block;
content: '';
top: 8px;
bottom: 8px;
left: 1px;
right: 1px;
background-color: var(--color-tint-1);
border-radius: var(--border-radius-menu);
opacity: 0;
}
@media (hover: hover) {
.landing__links a:hover::after {
opacity: 1;
}
}

View file

@ -1,11 +1,3 @@
.article__api-heading {
text-transform: uppercase;
color: var(--color-tint-5);
letter-spacing: 0.07em;
font-size: 12px;
font-weight: 400;
}
.article__parameters-table {
table-layout: fixed;
}

View file

@ -3,6 +3,7 @@ export type InputCategory = {
title: string
description: string
groups: InputGroup[]
hero: string | null
}
export type InputSection = {
@ -10,6 +11,7 @@ export type InputSection = {
title: string
description: string
categories: InputCategory[]
hero: string | null
sidebar_behavior: 'show-links' | 'show-title' | 'hidden' | 'reference'
}
@ -56,6 +58,8 @@ export interface Section extends ContentPage {
categories: Category[]
/** How the section should appear in the sidebar. */
sidebar_behavior: 'show-links' | 'show-title' | 'hidden' | 'reference'
/** The section's hero image (optional). */
hero: string | null
}
export interface Category extends ContentPage {
@ -66,6 +70,8 @@ export interface Category extends ContentPage {
index: number
/** The category's groups */
groups: Group[]
/** The category's hero image (optional). */
hero: string | null
}
export interface Group extends ContentPage {
@ -179,7 +185,6 @@ export type SidebarContentLink =
| SidebarContentArticleLink
export type SidebarContentList = {
headings?: ArticleHeadings
sectionId: string | null
categoryId: string | null
articleId: string | null

View file

@ -1400,7 +1400,136 @@ export const TldrawSelectionBackground: ({ bounds, rotation }: TLSelectionBackgr
export const TldrawSelectionForeground: MemoExoticComponent<({ bounds, rotation, }: TLSelectionForegroundProps) => JSX_2.Element | null>;
// @public (undocumented)
export const TldrawUi: React_2.NamedExoticComponent<TldrawUiProps>;
export const TldrawUi: React_2.NamedExoticComponent<{
children?: any;
hideUi?: boolean | undefined;
components?: Partial<{
ContextMenu: null | React_2.ComponentType<TLUiContextMenuProps>;
ActionsMenu: null | React_2.ComponentType<TLUiActionsMenuProps>;
HelpMenu: null | React_2.ComponentType<TLUiHelpMenuProps>;
ZoomMenu: null | React_2.ComponentType<TLUiZoomMenuProps>;
MainMenu: null | React_2.ComponentType<TLUiMainMenuProps>;
Minimap: null | React_2.ComponentType;
StylePanel: null | React_2.ComponentType<TLUiStylePanelProps>;
PageMenu: null | React_2.ComponentType;
NavigationPanel: null | React_2.ComponentType;
Toolbar: null | React_2.ComponentType;
KeyboardShortcutsDialog: null | React_2.ComponentType<TLUiKeyboardShortcutsDialogProps>;
QuickActions: null | React_2.ComponentType<TLUiQuickActionsProps>;
HelperButtons: null | React_2.ComponentType<TLUiHelperButtonsProps>;
DebugMenu: null | React_2.ComponentType;
MenuPanel: null | React_2.ComponentType;
TopPanel: null | React_2.ComponentType;
SharePanel: null | React_2.ComponentType;
}> | undefined;
renderDebugMenuItems?: (() => React_2.ReactNode) | undefined;
assetUrls?: (RecursivePartial<TLUiAssetUrls> & RecursivePartial<TLUiAssetUrls>) | undefined;
overrides?: Partial<{
actions: TLUiOverride<TLUiActionsContextType, {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
toolbar: TLUiOverride<TLUiToolbarSchemaContextType, {
tools: TLUiToolsContextType;
} & {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
tools: TLUiOverride<TLUiToolsContextType, {
insertMedia: () => void;
} & {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
translations: Record<string, Record<string, string>> | undefined;
}> | Partial<{
actions: TLUiOverride<TLUiActionsContextType, {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
toolbar: TLUiOverride<TLUiToolbarSchemaContextType, {
tools: TLUiToolsContextType;
} & {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
tools: TLUiOverride<TLUiToolsContextType, {
insertMedia: () => void;
} & {
addToast: (toast: Omit<TLUiToast, "id"> & {
id?: string | undefined;
}) => string;
removeToast: (id: string) => string;
clearToasts: () => void;
addDialog: (dialog: Omit<TLUiDialog, "id"> & {
id?: string | undefined;
}) => string;
clearDialogs: () => void;
removeDialog: (id: string) => string;
updateDialog: (id: string, newDialogData: Partial<TLUiDialog>) => string;
msg: (id?: string | undefined) => string;
isMobile: boolean;
}>;
translations: Record<string, Record<string, string>> | undefined;
}>[] | undefined;
onUiEvent?: TLUiEventHandler | undefined;
forceMobile?: boolean | undefined;
}>;
// @public
export interface TldrawUiBaseProps {
@ -1518,7 +1647,7 @@ export function TldrawUiPopoverContent({ side, children, align, sideOffset, alig
export function TldrawUiPopoverTrigger({ children }: TLUiPopoverTriggerProps): JSX_2.Element;
// @public
export type TldrawUiProps = TldrawUiBaseProps & TldrawUiContextProviderProps;
export type TldrawUiProps = Expand<TldrawUiBaseProps & TldrawUiContextProviderProps>;
// @internal (undocumented)
export const TldrawUiSlider: NamedExoticComponent<TLUiSliderProps>;

View file

@ -16204,16 +16204,808 @@
},
{
"kind": "Content",
"text": "<"
"text": "<{\n children?: any;\n hideUi?: boolean | undefined;\n components?: "
},
{
"kind": "Reference",
"text": "TldrawUiProps",
"canonicalReference": "tldraw!TldrawUiProps:type"
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": ">"
"text": "<{\n ContextMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiContextMenuProps",
"canonicalReference": "tldraw!TLUiContextMenuProps:interface"
},
{
"kind": "Content",
"text": ">;\n ActionsMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiActionsMenuProps",
"canonicalReference": "tldraw!TLUiActionsMenuProps:type"
},
{
"kind": "Content",
"text": ">;\n HelpMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiHelpMenuProps",
"canonicalReference": "tldraw!TLUiHelpMenuProps:type"
},
{
"kind": "Content",
"text": ">;\n ZoomMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiZoomMenuProps",
"canonicalReference": "tldraw!TLUiZoomMenuProps:type"
},
{
"kind": "Content",
"text": ">;\n MainMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiMainMenuProps",
"canonicalReference": "tldraw!TLUiMainMenuProps:type"
},
{
"kind": "Content",
"text": ">;\n Minimap: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n StylePanel: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiStylePanelProps",
"canonicalReference": "tldraw!TLUiStylePanelProps:interface"
},
{
"kind": "Content",
"text": ">;\n PageMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n NavigationPanel: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n Toolbar: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n KeyboardShortcutsDialog: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiKeyboardShortcutsDialogProps",
"canonicalReference": "tldraw!TLUiKeyboardShortcutsDialogProps:type"
},
{
"kind": "Content",
"text": ">;\n QuickActions: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiQuickActionsProps",
"canonicalReference": "tldraw!TLUiQuickActionsProps:type"
},
{
"kind": "Content",
"text": ">;\n HelperButtons: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": "<import(\"../..\")."
},
{
"kind": "Reference",
"text": "TLUiHelperButtonsProps",
"canonicalReference": "tldraw!TLUiHelperButtonsProps:type"
},
{
"kind": "Content",
"text": ">;\n DebugMenu: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n MenuPanel: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n TopPanel: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n SharePanel: null | "
},
{
"kind": "Reference",
"text": "React.ComponentType",
"canonicalReference": "@types/react!React.ComponentType:type"
},
{
"kind": "Content",
"text": ";\n }> | undefined;\n renderDebugMenuItems?: (() => "
},
{
"kind": "Reference",
"text": "React.ReactNode",
"canonicalReference": "@types/react!React.ReactNode:type"
},
{
"kind": "Content",
"text": ") | undefined;\n assetUrls?: (import(\"@tldraw/editor\")."
},
{
"kind": "Reference",
"text": "RecursivePartial",
"canonicalReference": "@tldraw/utils!RecursivePartial:type"
},
{
"kind": "Content",
"text": "<import(\"./assetUrls\")."
},
{
"kind": "Reference",
"text": "TLUiAssetUrls",
"canonicalReference": "tldraw!~TLUiAssetUrls:type"
},
{
"kind": "Content",
"text": "> & import(\"@tldraw/editor\")."
},
{
"kind": "Reference",
"text": "RecursivePartial",
"canonicalReference": "@tldraw/utils!RecursivePartial:type"
},
{
"kind": "Content",
"text": "<import(\"./assetUrls\")."
},
{
"kind": "Reference",
"text": "TLUiAssetUrls",
"canonicalReference": "tldraw!~TLUiAssetUrls:type"
},
{
"kind": "Content",
"text": ">) | undefined;\n overrides?: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<{\n actions: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./context/actions\")."
},
{
"kind": "Reference",
"text": "TLUiActionsContextType",
"canonicalReference": "tldraw!TLUiActionsContextType:type"
},
{
"kind": "Content",
"text": ", {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n toolbar: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./hooks/useToolbarSchema\")."
},
{
"kind": "Reference",
"text": "TLUiToolbarSchemaContextType",
"canonicalReference": "tldraw!TLUiToolbarSchemaContextType:type"
},
{
"kind": "Content",
"text": ", {\n tools: import(\"./hooks/useTools\")."
},
{
"kind": "Reference",
"text": "TLUiToolsContextType",
"canonicalReference": "tldraw!TLUiToolsContextType:type"
},
{
"kind": "Content",
"text": ";\n } & {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n tools: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./hooks/useTools\")."
},
{
"kind": "Reference",
"text": "TLUiToolsContextType",
"canonicalReference": "tldraw!TLUiToolsContextType:type"
},
{
"kind": "Content",
"text": ", {\n insertMedia: () => void;\n } & {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n translations: "
},
{
"kind": "Reference",
"text": "Record",
"canonicalReference": "!Record:type"
},
{
"kind": "Content",
"text": "<string, "
},
{
"kind": "Reference",
"text": "Record",
"canonicalReference": "!Record:type"
},
{
"kind": "Content",
"text": "<string, string>> | undefined;\n }> | "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<{\n actions: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./context/actions\")."
},
{
"kind": "Reference",
"text": "TLUiActionsContextType",
"canonicalReference": "tldraw!TLUiActionsContextType:type"
},
{
"kind": "Content",
"text": ", {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n toolbar: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./hooks/useToolbarSchema\")."
},
{
"kind": "Reference",
"text": "TLUiToolbarSchemaContextType",
"canonicalReference": "tldraw!TLUiToolbarSchemaContextType:type"
},
{
"kind": "Content",
"text": ", {\n tools: import(\"./hooks/useTools\")."
},
{
"kind": "Reference",
"text": "TLUiToolsContextType",
"canonicalReference": "tldraw!TLUiToolsContextType:type"
},
{
"kind": "Content",
"text": ";\n } & {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n tools: import(\"./overrides\")."
},
{
"kind": "Reference",
"text": "TLUiOverride",
"canonicalReference": "tldraw!~TLUiOverride:type"
},
{
"kind": "Content",
"text": "<import(\"./hooks/useTools\")."
},
{
"kind": "Reference",
"text": "TLUiToolsContextType",
"canonicalReference": "tldraw!TLUiToolsContextType:type"
},
{
"kind": "Content",
"text": ", {\n insertMedia: () => void;\n } & {\n addToast: (toast: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/toasts\")."
},
{
"kind": "Reference",
"text": "TLUiToast",
"canonicalReference": "tldraw!TLUiToast:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n removeToast: (id: string) => string;\n clearToasts: () => void;\n addDialog: (dialog: "
},
{
"kind": "Reference",
"text": "Omit",
"canonicalReference": "!Omit:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ", \"id\"> & {\n id?: string | undefined;\n }) => string;\n clearDialogs: () => void;\n removeDialog: (id: string) => string;\n updateDialog: (id: string, newDialogData: "
},
{
"kind": "Reference",
"text": "Partial",
"canonicalReference": "!Partial:type"
},
{
"kind": "Content",
"text": "<import(\"./context/dialogs\")."
},
{
"kind": "Reference",
"text": "TLUiDialog",
"canonicalReference": "tldraw!TLUiDialog:interface"
},
{
"kind": "Content",
"text": ">) => string;\n msg: (id?: string | undefined) => string;\n isMobile: boolean;\n }>;\n translations: "
},
{
"kind": "Reference",
"text": "Record",
"canonicalReference": "!Record:type"
},
{
"kind": "Content",
"text": "<string, "
},
{
"kind": "Reference",
"text": "Record",
"canonicalReference": "!Record:type"
},
{
"kind": "Content",
"text": "<string, string>> | undefined;\n }>[] | undefined;\n onUiEvent?: import(\"./context/events\")."
},
{
"kind": "Reference",
"text": "TLUiEventHandler",
"canonicalReference": "tldraw!TLUiEventHandler:type"
},
{
"kind": "Content",
"text": " | undefined;\n forceMobile?: boolean | undefined;\n}>"
}
],
"fileUrlPath": "packages/tldraw/src/lib/ui/TldrawUi.tsx",
@ -16222,7 +17014,7 @@
"name": "TldrawUi",
"variableTypeTokenRange": {
"startIndex": 1,
"endIndex": 5
"endIndex": 181
}
},
{
@ -18325,12 +19117,21 @@
{
"kind": "TypeAlias",
"canonicalReference": "tldraw!TldrawUiProps:type",
"docComment": "/**\n * Props for the {@link tldraw#Tldraw} and {@link TldrawUi} components.\n *\n * @public\n */\n",
"docComment": "/**\n * Props for the {@link @tldraw/tldraw#Tldraw} and {@link TldrawUi} components.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export type TldrawUiProps = "
},
{
"kind": "Reference",
"text": "Expand",
"canonicalReference": "@tldraw/utils!Expand:type"
},
{
"kind": "Content",
"text": "<"
},
{
"kind": "Reference",
"text": "TldrawUiBaseProps",
@ -18345,6 +19146,10 @@
"text": "TldrawUiContextProviderProps",
"canonicalReference": "tldraw!TldrawUiContextProviderProps:interface"
},
{
"kind": "Content",
"text": ">"
},
{
"kind": "Content",
"text": ";"
@ -18355,7 +19160,7 @@
"name": "TldrawUiProps",
"typeTokenRange": {
"startIndex": 1,
"endIndex": 4
"endIndex": 7
}
},
{

View file

@ -1,5 +1,5 @@
import { ToastProvider } from '@radix-ui/react-toast'
import { useEditor, useValue } from '@tldraw/editor'
import { Expand, useEditor, useValue } from '@tldraw/editor'
import classNames from 'classnames'
import React, { ReactNode } from 'react'
import { TLUiAssetUrlOverrides } from './assetUrls'
@ -23,13 +23,6 @@ import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts'
import { useReadonly } from './hooks/useReadonly'
import { useTranslation } from './hooks/useTranslation/useTranslation'
/**
* Props for the {@link tldraw#Tldraw} and {@link TldrawUi} components.
*
* @public
*/
export type TldrawUiProps = TldrawUiBaseProps & TldrawUiContextProviderProps
/**
* Base props for the {@link tldraw#Tldraw} and {@link TldrawUi} components.
*
@ -60,6 +53,13 @@ export interface TldrawUiBaseProps {
assetUrls?: TLUiAssetUrlOverrides
}
/**
* Props for the {@link @tldraw/tldraw#Tldraw} and {@link TldrawUi} components.
*
* @public
*/
export type TldrawUiProps = Expand<TldrawUiBaseProps & TldrawUiContextProviderProps>
/**
* @public
*/

791
yarn.lock

File diff suppressed because it is too large Load diff