> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Диалог

> Отобразите целевую задачу поверх текущей страницы.

## Обзор

Используйте `Dialog` для форм, сведений и других задач, открывающихся поверх страницы. Он управляет фокусом, закрытием с клавиатуры, внешними щелчками и прокруткой. Используйте [AlertDialog](https://docs.twenty.com/ru/ui/primitives/surfaces/alert-dialog.md), когда пользователь должен явно ответить на решение.

Этот API предназначен для автономного Twenty UI и хост-приложения Twenty. Фронтальные компоненты должны использовать [`openCommandConfirmationModal`](https://docs.twenty.com/ru/developers/extend/apps/layout/front-components#host-communication-api) из SDK вместо непосредственного рендеринга `Dialog` или `AlertDialog`. Нативные диалоговые окна и всплывающие элементы браузера также запрещены в средстве рендеринга фронтальных компонентов.

**Light**

[Пример диалога (light)](https://storybook.twenty.com/iframe.html?id=ui-surfaces-dialog--display\&viewMode=story\&globals=colorScheme:light)

**Dark**

[Пример диалога (dark)](https://storybook.twenty.com/iframe.html?id=ui-surfaces-dialog--display\&viewMode=story\&globals=colorScheme:dark)

[Open in Storybook](https://storybook.twenty.com/?path=/story/ui-surfaces-dialog--display)

## Использование

### Неконтролируемое состояние

По умолчанию `Root` управляет видимостью. Задайте `defaultOpen` для его начального состояния. Триггеры, элементы управления закрытием, Escape и внешние щелчки обновляют это состояние.

```tsx theme={null}
import { Button, Field, Input } from 'twenty-ui/primitives/input';
import { Dialog } from 'twenty-ui/primitives/surfaces';

export const AccountDialog = () => (
  <Dialog.Root defaultOpen={false}>
    <Dialog.Trigger render={<Button>Edit account</Button>} />
    <Dialog.Portal>
      <Dialog.Backdrop />
      <Dialog.Viewport>
        <Dialog.Popup>
          <Dialog.Header>
            <Dialog.Title>Edit account</Dialog.Title>
            <Dialog.Description>Update the account details.</Dialog.Description>
          </Dialog.Header>
          <Dialog.Body>
            <Field.Root name="company">
              <Field.Label>Company name</Field.Label>
              <Input defaultValue="Acme" />
            </Field.Root>
          </Dialog.Body>
          <Dialog.Footer>
            <Dialog.Close render={<Button variant="outline">Close</Button>} />
            <Dialog.Close render={<Button>Save</Button>} />
          </Dialog.Footer>
        </Dialog.Popup>
      </Dialog.Viewport>
    </Dialog.Portal>
  </Dialog.Root>
);
```

## Структура

```text theme={null}
Dialog.Root
├── Dialog.Trigger
└── Dialog.Portal
    ├── Dialog.Backdrop
    └── Dialog.Viewport
        └── Dialog.Popup
            ├── Dialog.Header
            │   ├── Dialog.Title
            │   └── Dialog.Description
            ├── Dialog.Body
            └── Dialog.Footer
                └── Dialog.Close
```

| Часть | Нативный элемент и цель ref |
| - | - |
| `Root` | Координирует видимость и модальное поведение. Не рендерит DOM-узел и не принимает нативные атрибуты или DOM ref. |
| `Триггер` | По умолчанию — кнопка. Открывает диалоговое окно и предоставляет цель для восстановления фокуса. |
| `Portal` | Div портала. Управляет целевым контейнером и тем, остаётся ли закрытое содержимое смонтированным. |
| `Backdrop` | Div фона под всплывающим окном. Необязательно; не указывайте его, если видимый фон не нужен. |
| `Viewport` | Div для позиционирования вокруг всплывающего окна. |
| `Popup` | Div диалогового окна. Управляет содержимым, размером, целями фокуса и семантикой диалогового окна. |
| `Заголовок` | По умолчанию — `h2`. Предоставляет доступное имя. При его отсутствии укажите `aria-label` для `Popup`. |
| `Description` | По умолчанию — абзац. Связывает вспомогательный текст с диалогом. |
| `Header`, `Body`, `Footer` | Необязательные div, располагающие заголовки, содержимое и действия. |
| `Закрыть` | По умолчанию — кнопка. Предоставляет видимое действие закрытия, в том числе для программ чтения с экрана на сенсорных устройствах. |

Явно соберите `Portal`, `Backdrop`, `Viewport` и `Popup`. Каждая DOM-часть принимает собственные нативные атрибуты, обработчики, `className`, `style`, ref и композицию `render`. Ref указывает на отрендеренный элемент этой части. `Popup` не создаёт портал, фон или область просмотра.

## Контролируемое состояние

Передайте `open` и `onOpenChange`, когда приложение управляет видимостью. Колбэк получает запрошенное состояние и сведения о событии Base UI, включая `reason`, `event`, `trigger` и `cancel()`. Обновите состояние, чтобы принять изменение, или вызовите `eventDetails.cancel()`, чтобы отклонить его. `onOpenChangeComplete` выполняется, когда завершается анимация открытия или закрытия.

```tsx theme={null}
import { useState } from 'react';
import { Button, Field, Input } from 'twenty-ui/primitives/input';
import { Dialog } from 'twenty-ui/primitives/surfaces';

export const AccountDialog = () => {
  const [open, setOpen] = useState(false);

  return (
    <Dialog.Root open={open} onOpenChange={setOpen}>
      <Dialog.Trigger render={<Button>Edit account</Button>} />
      <Dialog.Portal>
        <Dialog.Backdrop />
        <Dialog.Viewport>
          <Dialog.Popup>
            <Dialog.Header>
              <Dialog.Title>Edit account</Dialog.Title>
              <Dialog.Description>
                Update the account details.
              </Dialog.Description>
            </Dialog.Header>
            <Dialog.Body>
              <Field.Root name="company">
                <Field.Label>Company name</Field.Label>
                <Input defaultValue="Acme" />
              </Field.Root>
            </Dialog.Body>
            <Dialog.Footer>
              <Dialog.Close render={<Button variant="outline">Close</Button>} />
              <Dialog.Close render={<Button>Save</Button>} />
            </Dialog.Footer>
          </Dialog.Popup>
        </Dialog.Viewport>
      </Dialog.Portal>
    </Dialog.Root>
  );
};
```

Для асинхронной формы не закрывайте диалог во время отправки. Закройте его после успеха и отображайте ошибки внутри диалога.

## Композиция

`Trigger` и `Close` принимают `render` для композиции с `Button`, как показано выше. Пользовательские обёртки должны [перенаправлять предоставленные свойства и ссылки](https://docs.twenty.com/ru/ui/primitives/overview#custom-components). DOM-части сохраняют зависящие от состояния имена классов, стили и контракты колбэков `render` из Base UI. `Header`, `Body` и `Footer` сохраняют стилизованную компоновку и нативную композицию div.

Вложите другой `Dialog.Root` во всплывающее окно, чтобы открыть второй диалог. При закрытии вложенного диалога фокус возвращается к его триггеру в родительском диалоге.

Чтобы открыть одно диалоговое окно из триггеров за пределами `Root`, один раз создайте дескриптор с помощью `Dialog.createHandle\<TPayload>()` и передайте его в `handle` как для `Root`, так и для каждого `Trigger`. Значения `payload` триггера доступны в функции рендеринга `Root`. `Dialog.Handle` и публичный тип `DialogHandle` предоставляют контракт установленного дескриптора:

| Член | Назначение |
| - | - |
| `open(triggerId)` | Открывает с соответствующим триггером в качестве активного триггера. |
| `open(null)` | Открывает без привязки к триггеру. |
| `openWithPayload(payload)` | Открывает с типизированной полезной нагрузкой и без связанного триггера. |
| `close()` | Запрашивает закрытие. |
| `isOpen` | Проверяет, открыто ли связанное диалоговое окно. |

Императивные действия выполняются, только пока связанный Root смонтирован. `actionsRef` Root также предоставляет `close()` и `unmount()` для явного управления переходами. Чтобы управлять внешней анимацией закрытия, вызовите `eventDetails.preventUnmountOnClose()` в `onOpenChange`, затем вызовите действие `unmount()`, когда анимация завершится.

`Title` использует `Heading` и по умолчанию отображается как `h2` с крупным шрифтом, основным цветом текста, выравниванием по центру и отступом spacing-4 под ним. Используйте `level`, чтобы изменить уровень заголовка независимо от `size`, или `color`, чтобы изменить цвет его текста. Нативные `className`, `style`, ссылки и `render` перенаправляются в заголовок. При использовании `render` сохраняйте элемент заголовка. `Description` выровнено по центру, как `Title`; AlertDialog сохраняет оба выровненными по левому краю.

`Popup` не имеет внутренних отступов. `Header`, `Body` и `Footer` обеспечивают внутренний отступ, поэтому содержимое, размещенное непосредственно в `Popup`, располагается у его краев.

## Фокус, прокрутка и закрытие

`Root.modal` управляет границей взаимодействия:

| Значение | Фокус | Прокрутка страницы и внешнее взаимодействие |
| - | - | - |
| `true` (по умолчанию) | Ограничено внутри диалогового окна | Прокрутка страницы и внешнее взаимодействие заблокированы. |
| `"trap-focus"` | Удерживается внутри диалога | Прокрутка страницы и взаимодействие вне окна остаются доступными. |
| `ложь` | Может покинуть диалог | Прокрутка страницы и внешнее взаимодействие остаются доступными. |

Не указывайте `Backdrop`, если видимый фон не нужен. Для немодального диалогового окна, область просмотра которого должна пропускать события указателя на страницу, используйте `\<Dialog.Viewport data-backdrop-hidden="true">`; Popup остаётся интерактивным. Само по себе отсутствие визуального фона не изменяет `Root.modal`.

Задайте для `Popup.initialFocus` или `Popup.finalFocus` ссылку либо обратный вызов, чтобы выбрать цели фокуса; `false` отключает это автоматическое перемещение фокуса. Колбэки фокуса получают тип взаимодействия и сохраняют поведение возврата boolean, element, null и undefined из Base UI. При обычном закрытии фокус восстанавливается на триггере или ранее сфокусированном элементе.

`Root.disablePointerDismissal` предотвращает запросы на закрытие при внешних щелчках. Чтобы предотвратить закрытие по Escape, отмените изменение `escape-key` в `onOpenChange`. Всегда предоставляйте видимый способ закрыть модальный диалог.

## Размеры и порталы

`Popup.size` принимает `sm`, `compact`, `md`, `lg`, `xl` и `fullscreen`; по умолчанию используется `md`. Длинное содержимое прокручивается внутри всплывающего окна. Ширина ограничена областью просмотра.

Укажите `Portal.container`, чтобы выбрать назначение:

| Значение | Разрешение |
| - | - |
| Не указан или `undefined` | Использует ближайший контейнер области темы. При его отсутствии Base UI использует родительский портал или body документа. |
| Element или `ShadowRoot` | Использует это явно указанное назначение вместо области темы. |
| Ref | Base UI разрешает его текущий элемент. Ref, текущее значение которого равно null, возвращается к родительскому порталу или body документа. |
| `null` | Ожидает без монтирования. Укажите назначение при последующем рендеринге для монтирования. |

`Portal.keepMounted` сохраняет содержимое и состояние формы в закрытом состоянии. `Viewport` и `Popup` переносят предоставленное направление текста во внешний контейнер; их явные props `dir` имеют приоритет. Без провайдера направления или явного `dir` они наследуют его от назначения. См. [темизацию](https://docs.twenty.com/ru/ui/theming.md) и [DirectionProvider](https://docs.twenty.com/ru/ui/primitives/layout/direction-provider.md).

Настраивайте `Backdrop` и `Viewport` через их собственные props. Их нативные атрибуты, обработчики, refs и `render` применяются к этим элементам независимо от Popup. `forceRender` Backdrop при необходимости сохраняет видимым фон вложенного диалогового окна. Состояния открытия и перехода Base UI остаются доступными для стилей, зависящих от состояния, и колбэков рендеринга.

## Миграция

Оберните существующее содержимое `Dialog.Popup` в `Dialog.Portal` и `Dialog.Viewport`, а внутри Portal добавьте соседний `Dialog.Backdrop`. Переместите `container` и `keepMounted` из Popup в Portal. Переместите прежние props `backdrop` в Backdrop; замените `backdrop={false}` отсутствием Backdrop. Переместите `viewportProps` в Viewport, сохранив `data-backdrop-hidden="true"`, если область просмотра должна пропускать внешние события указателя. Сохраните `size`, `initialFocus`, `finalFocus`, нативные атрибуты popup и refs popup в Popup. Объединённые props сборки Popup удалены.

Root, Trigger, Close, Title, Description, Header, Body, Footer и существующие дескрипторы сохраняют свои роли. Публичные props частей, состояния, действия и типы сведений о событиях экспортируются из `twenty-ui/primitives/surfaces`.

## Свойства

### Dialog.Root

**Root.actionsRef** `RefObject\<DialogRootActions | null\>`

A ref to imperative actions.

* `unmount`: Ends the closing phase of the dialog after an externally controlled closing animation finishes.
  Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the dialog completes closing on its own.
  Whether it leaves the DOM is decided by `keepMounted` on the portal.
* `close`: Closes the dialog imperatively when called.

**Root.children** `ReactNode | PayloadChildRenderFunction\<Payload\>`

Parts or a render function receiving the active trigger payload. Root renders no DOM node.

**Root.defaultOpen** `boolean` (default: false)

Whether the dialog is initially open.

To render a controlled dialog, use the `open` prop instead.

**Root.defaultTriggerId** `string | null`

ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog.

**Root.disablePointerDismissal** `boolean` (default: false)

Whether to prevent the dialog from closing on outside presses.
For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it.

**Root.handle** `DialogHandle\<Payload\>`

Connects detached triggers and imperative dialog actions.

**Root.modal** `boolean | "trap-focus"` (default: true)

Determines if the dialog enters a modal state when open.

* `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled.
* `false`: user interaction with the rest of the document is allowed.
* `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.

When `modal` is `true` or `'trap-focus'`, render `<Dialog.Close>` inside `<Dialog.Popup>` so
touch screen readers can escape the popup.

**Root.onOpenChange** `((open: boolean, eventDetails: DialogRootChangeEventDetails) =\> void)`

Receives the requested state and Base UI event details, including reason, event, trigger and cancel().

**Root.onOpenChangeComplete** `((open: boolean) =\> void)`

Event handler called after any animations complete when the dialog is opened or closed.

**Root.open** `boolean`

Whether the dialog is currently open.

**Root.triggerId** `string | null`

ID of the trigger that the dialog is associated with.
This is useful in conjunction with the `open` prop to create a controlled dialog.
There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set).

### Dialog.Trigger

**Trigger.className** `string | ((state: DialogTriggerState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Trigger.handle** `DialogHandle\<Payload\>`

A handle to associate the trigger with a dialog.
Can be created with the Dialog.createHandle() method.

**Trigger.id** `string`

ID of the trigger. In addition to being forwarded to the rendered element,
it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop).

**Trigger.nativeButton** `boolean` (default: true)

Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`).

**Trigger.payload** `Payload`

A payload to pass to the dialog when it is opened.

**Trigger.ref** `((((instance: HTMLButtonElement | null) =\> void | (() =\> VoidOrUndefinedOnly)) | RefObject\<HTMLButtonElement | null\>) & (((instance: HTMLElement | null) =\> void | (() =\> VoidOrUndefinedOnly)) | RefObject\<...\>)) | null`

Ref to the trigger button, or the element supplied through render.

**Trigger.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogTriggerState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Trigger.style** `CSSProperties | ((state: DialogTriggerState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Portal

**Portal.className** `string | ((state: DialogPortalState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Portal.container** `HTMLElement | ShadowRoot | RefObject\<HTMLElement | ShadowRoot | null\> | null`

Portal destination. Omit to use the nearest theme scope, then the parent portal or document body. Explicit null defers mounting; an element, ShadowRoot or ref keeps Base UI resolution.

**Portal.keepMounted** `boolean` (default: false)

Keeps the portal and its content mounted while closed.

**Portal.ref** `Ref\<HTMLDivElement\>`

Ref to the portal div, or the element supplied through render.

**Portal.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogPortalState\>`

Composes the portal element. Native props and handlers target it.

**Portal.style** `CSSProperties | ((state: DialogPortalState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Backdrop

**Backdrop.className** `string | ((state: DialogBackdropState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Backdrop.forceRender** `boolean` (default: false)

Renders the backdrop even when this dialog is nested.

**Backdrop.ref** `Ref\<HTMLDivElement\>`

Ref to the backdrop div, or the element supplied through render.

**Backdrop.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogBackdropState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Backdrop.style** `CSSProperties | ((state: DialogBackdropState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Viewport

**Viewport.children** `ReactNode`

Popup and any other content within the positioning viewport.

**Viewport.className** `string | ((state: DialogViewportState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Viewport.ref** `Ref\<HTMLDivElement\>`

Ref to the viewport div, or the element supplied through render.

**Viewport.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogViewportState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Viewport.style** `CSSProperties | ((state: DialogViewportState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Popup

**Popup.children** `ReactNode`

Dialog content. Compose inside Viewport and Portal; Popup does not create those parts or a Backdrop.

**Popup.className** `string | ((state: DialogPopupState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Popup.finalFocus** `boolean | RefObject\<HTMLElement | null\> | ((closeType: InteractionType) =\> boolean | void | HTMLElement | null)`

Controls focus restoration on closing. Accepts a boolean, element ref or callback receiving the interaction type.

**Popup.initialFocus** `boolean | RefObject\<HTMLElement | null\> | ((openType: InteractionType) =\> boolean | void | HTMLElement | null)`

Controls focus on opening. Accepts a boolean, element ref or callback receiving the interaction type.

**Popup.ref** `Ref\<HTMLDivElement\>`

Ref to the popup div, or the element supplied through render.

**Popup.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogPopupState\>`

Composes the popup element while retaining native props, handlers, dialog semantics and focus behavior.

**Popup.size** `"compact" | "fullscreen" | "lg" | "md" | "sm" | "xl"` (default: md)

Width of the dialog, or `fullscreen` to fill the viewport.

**Popup.style** `CSSProperties | ((state: DialogPopupState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Title

**Title.className** `string | ((state: DialogTitleState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Title.color** `"primary" | "secondary" | "tertiary"` (default: primary)

Theme font color. Defaults to `primary`.

**Title.level** `1 | 2 | 3 | 4 | 5 | 6` (default: 2)

Semantic heading level, from `h1` through `h6`. Does not change the visual size. Defaults to `2`.

**Title.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogTitleState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Title.size** `"lg" | "md" | "sm" | "xl" | "xs" | "xxl"` (default: lg)

Visual font size, independent of the heading level. Defaults to `lg`.

**Title.style** `CSSProperties | ((state: DialogTitleState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Description

**Description.className** `string | ((state: DialogDescriptionState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Description.ref** `Ref\<HTMLParagraphElement\>`

Ref to the description paragraph, or the element supplied through render.

**Description.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogDescriptionState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Description.style** `CSSProperties | ((state: DialogDescriptionState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Close

**Close.className** `string | ((state: DialogCloseState) =\> string | undefined)`

CSS class applied to the element, or a function that
returns a class based on the component's state.

**Close.nativeButton** `boolean` (default: true)

Whether the component renders a native `<button>` element when replacing it
via the `render` prop.
Set to `false` if the rendered element is not a button (for example, `<div>`).

**Close.ref** `Ref\<HTMLButtonElement\>`

Ref to the close button, or the element supplied through render.

**Close.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, DialogCloseState\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

**Close.style** `CSSProperties | ((state: DialogCloseState) =\> CSSProperties | undefined)`

Style applied to the element, or a function that
returns a style object based on the component's state.

### Dialog.Header

**Header.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, \{\}\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

### Dialog.Body

**Body.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, \{\}\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.

### Dialog.Footer

**Footer.render** `ReactElement\<unknown, string | JSXElementConstructor\<any\>\> | ComponentRenderFn\<HTMLProps, \{\}\>`

Allows you to replace the component's HTML element
with a different tag, or compose it with another component.

Accepts a `ReactElement` or a function that returns the element to render.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.