Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/shikijs/shiki-magic-move
Smoothly animated code blocks with Shiki
https://github.com/shikijs/shiki-magic-move
Last synced: 3 days ago
JSON representation
Smoothly animated code blocks with Shiki
- Host: GitHub
- URL: https://github.com/shikijs/shiki-magic-move
- Owner: shikijs
- License: mit
- Created: 2024-02-22T19:25:54.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2024-10-21T06:04:05.000Z (19 days ago)
- Last Synced: 2024-10-31T11:37:00.631Z (9 days ago)
- Language: TypeScript
- Homepage: https://shiki-magic-move.netlify.app/
- Size: 629 KB
- Stars: 1,237
- Watchers: 3
- Forks: 40
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# shiki-magic-move
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![bundle][bundle-src]][bundle-href]
[![JSDocs][jsdocs-src]][jsdocs-href]
[![License][license-src]][license-href]Smoothly animated code blocks with Shiki. [Online Demo](https://shiki-magic-move.netlify.app/).
Shiki Magic Move is a low-level library for animating code blocks, and uses [Shiki](https://shiki.style/) as the syntax highlighter. You usually want to use it with a high-level integration like [Slidev](https://sli.dev/guide/syntax#shiki-magic-move).
At the core of the `shiki-magic-move` package is a framework-agnostic [core](./src/core.ts), and [renderer](./src/renderer.ts) — there are also framework wrappers for [Vue](./src/vue), [React](./src/react), and [Svelte](./src/svelte).
Each of the framework wrappers provides the following components:
- `ShikiMagicMove` - the main component to wrap the code block
- `ShikiMagicMovePrecompiled` - animations for compiled tokens, without the dependency on Shiki
- `ShikiMagicMoveRenderer` - the low-level renderer componentThe `ShikiMagicMove` component requires you to provide a Shiki highlighter instance, and the styles are also required, and provided by `shiki-magic-move`. Whenever the `code` changes, the component will animate the changes.
## Installation
You're going to need Shiki Magic Move for animating the code blocks, and Shiki for syntax highlighting.
```bash
npm i shiki-magic-move shiki
```## Usage
### Vue
Import `shiki-magic-move/vue`, and pass the highlighter instance to the `ShikiMagicMove` component.
```vue
import { getHighlighter } from 'shiki'
import { ShikiMagicMove } from 'shiki-magic-move/vue'
import { ref } from 'vue'import 'shiki-magic-move/dist/style.css'
const highlighter = await getHighlighter({
themes: ['nord'],
langs: ['javascript', 'typescript'],
})const code = ref(`const hello = 'world'`)
function animate() {
code.value = `let hi = 'hello'`
}
Animate
```
### React
Import `shiki-magic-move/react`, and pass the highlighter instance to the `ShikiMagicMove` component.
```tsx
import { useEffect, useState } from 'react'
import { getHighlighter, type HighlighterCore } from 'shiki'
import { ShikiMagicMove } from 'shiki-magic-move/react'import 'shiki-magic-move/dist/style.css'
function App() {
const [code, setCode] = useState(`const hello = 'world'`)
const [highlighter, setHighlighter] = useState()useEffect(() => {
async function initializeHighlighter() {
const highlighter = await getHighlighter({
themes: ['nord'],
langs: ['javascript', 'typescript'],
})
setHighlighter(highlighter)
}
initializeHighlighter()
}, [])function animate() {
setCode(`let hi = 'hello'`)
}return (
{highlighter && (
<>
Animate
>
)}
)
}
```### Solid
Import `shiki-magic-move/solid`, and pass the highlighter instance to the `ShikiMagicMove` component.
```tsx
import { getHighlighter, type HighlighterCore } from 'shiki'
import { ShikiMagicMove } from 'shiki-magic-move/solid'
import { createResource, createSignal } from 'solid-js'import 'shiki-magic-move/dist/style.css'
function App() {
const [code, setCode] = createSignal(`const hello = 'world'`)const [highlighter] = createResource(async () => {
const newHighlighter = await createHighlighter({
themes: Object.keys(bundledThemes),
langs: Object.keys(bundledLanguages),
})return newHighlighter
})function animate() {
setCode(`let hi = 'hello'`)
}return (
{highlighter => (
<>
Animate
>
)}
)
}
```### Svelte
Import `shiki-magic-move/svelte`, and pass the highlighter instance to the `ShikiMagicMove` component.
```svelte
import { getHighlighter } from 'shiki'
import { ShikiMagicMove } from 'shiki-magic-move/svelte'import 'shiki-magic-move/dist/style.css'
const highlighter = getHighlighter({
themes: ['nord'],
langs: ['javascript', 'typescript'],
})let code = $state(`const hello = 'world'`)
function animate() {
code = `let hi = 'hello'`
}{#await highlighter then highlighter}
Animate
{/await}
```### `ShikiMagicMovePrecompiled`
`ShikiMagicMovePrecompiled` is a lighter version of `ShikiMagicMove` that doesn't require Shiki. It's useful when you want to animate the compiled tokens directly. For example, in Vue:
```vue
import { ShikiMagicMovePrecompiled } from 'shiki-magic-move/vue'
import { ref } from 'vue'const step = ref(1)
const compiledSteps = [/* Compiled token steps */]
Next
```
To get the compiled tokens, you can run this somewhere else and serialize them into the component:
```ts
import { getHighlighter } from 'shiki'
import { codeToKeyedTokens, createMagicMoveMachine } from 'shiki-magic-move/core'const shiki = await getHighlighter({
theme: 'nord',
langs: ['javascript', 'typescript'],
})const codeSteps = [
`const hello = 'world'`,
`let hi = 'hello'`,
]const machine = createMagicMoveMachine(
code => codeToKeyedTokens(shiki, code, {
lang: 'ts',
theme: 'nord',
}),
{
// options
}
)const compiledSteps = codeSteps.map(code => machine.commit(code).current)
// Pass `compiledSteps` to the precompiled component
// If you do this on server-side or build-time, you can serialize `compiledSteps` into JSON
```## How it works
You can read [The Magic In Shiki Magic Move](https://antfu.me/posts/shiki-magic-move) to understand how Shiki Magic Move works.
## Sponsors
## License
[MIT](./LICENSE) License © 2023-PRESENT [Anthony Fu](https://github.com/antfu)
[npm-version-src]: https://img.shields.io/npm/v/shiki-magic-move?style=flat&colorA=080f12&colorB=1fa669
[npm-version-href]: https://npmjs.com/package/shiki-magic-move
[npm-downloads-src]: https://img.shields.io/npm/dm/shiki-magic-move?style=flat&colorA=080f12&colorB=1fa669
[npm-downloads-href]: https://npmjs.com/package/shiki-magic-move
[bundle-src]: https://img.shields.io/bundlephobia/minzip/shiki-magic-move?style=flat&colorA=080f12&colorB=1fa669&label=minzip
[bundle-href]: https://bundlephobia.com/result?p=shiki-magic-move
[license-src]: https://img.shields.io/github/license/shikijs/shiki-magic-move.svg?style=flat&colorA=080f12&colorB=1fa669
[license-href]: https://github.com/shikijs/shiki-magic-move/blob/main/LICENSE
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
[jsdocs-href]: https://www.jsdocs.io/package/shiki-magic-move