Typewriter
Печатная машинка: текст набирается посимвольно с мигающей кареткой — чистый CSS (steps).
Пропсы
Разобрано из кода записи: обязательные — без «?», у остальных показано значение по умолчанию.
| Проп | Тип | По умолчанию | Что это |
|---|---|---|---|
| text? | string | "Motiva — premium animations" |
Установка
npx shadcn@latest add https://motiva.pages.dev/r/typewriter.jsonЧто нужно в проекте до установки
Файл
components.jsonв корнеИз него CLI узнаёт, куда класть файлы. Алиасы — в такой форме:
"aliases": { "components": "@/components", "lib": "@/lib" }Нет файла — установка не начнётся вовсе.
Алиас
@объявлен дваждыВ корневом
tsconfig.jsonи в конфиге сборщика. В Vite корневой tsconfig часто содержит толькоreferences— этого мало."paths": { "@/*": ["./src/*"] } // tsconfig.json resolve.alias = { "@": "/src" } // vite.config.tsБез
pathsCLI молча создаёт папку с именем@.Токены подключены один раз на приложение
Они приезжают вместе с записью — достаточно импортировать их в точке входа:
import "@/styles/motiva-tokens.css";Без них блок потеряет цвета, ритм и тему.
Своя типографика не спорит с блоком
Наследуемые свойства протекают внутрь:
text-align: centerна обёртке отцентрует содержимое секции. То же касаетсяfont-familyиline-height.Проект без TypeScript? всё равно нужен tsconfig
CLI грузит
tsconfig.jsonбезусловно, а при"tsx": falseидёт заjsconfig.jsonи падает так же. Минимум — файл сpathsи"tsx": trueвcomponents.json.Приехавший рядом
.tsxможно не трогать — вам нужен.vanilla.js.
Экспорт
Код
.tw {
font-family: ui-monospace, "JetBrains Mono", monospace;
font-size: 1.6rem;
font-weight: 600;
color: oklch(0.92 0.01 265);
}
.tw-text {
display: inline-block;
overflow: hidden;
white-space: nowrap;
/* базовая ширина = полный текст → при data-shot/no-anim текст виден целиком */
width: calc(var(--n, 27) * 1ch);
border-right: 2px solid oklch(0.72 0.15 220);
animation:
tw-type 2.4s steps(28) both,
tw-blink 0.75s step-end infinite;
}
@keyframes tw-type {
from {
width: 0;
}
}
@keyframes tw-blink {
50% {
border-color: transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.tw-text {
animation: none;
}
}
import { type CSSProperties } from "react";
import "./typewriter.css";
/** Эффект печатной машинки на чистом CSS (steps() + мигающий каретка). Ширина = длина текста. */
export function Typewriter({ text = "Motiva — premium animations" }: { text?: string }) {
return (
<span className="tw">
<span className="tw-text" style={{ "--n": text.length } as CSSProperties}>
{text}
</span>
</span>
);
}