241 lines
6.2 KiB
JavaScript
241 lines
6.2 KiB
JavaScript
import { createMagicMoveMachine, codeToKeyedTokens, toKeyedTokens, syncTokenKeys } from './core.mjs';
|
|
import { MagicMoveRenderer } from './renderer.mjs';
|
|
import 'diff-match-patch-es';
|
|
import 'ohash';
|
|
|
|
class ShikiMagicMoveRenderer extends HTMLElement {
|
|
_animated = true;
|
|
_class = '';
|
|
get animated() {
|
|
return this._animated;
|
|
}
|
|
set animated(value) {
|
|
this._animated = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get tokens() {
|
|
return this._tokens;
|
|
}
|
|
set tokens(value) {
|
|
this._tokens = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get previous() {
|
|
return this._previous;
|
|
}
|
|
set previous(value) {
|
|
this._previous = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get options() {
|
|
return this._options;
|
|
}
|
|
set options(value) {
|
|
this._options = value;
|
|
if (this.renderer) Object.assign(this.renderer.options, this.options);
|
|
this.propertyChangedCallback();
|
|
}
|
|
get class() {
|
|
return this._class;
|
|
}
|
|
set class(value) {
|
|
this._class = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
batchUpdate = false;
|
|
hasUpdated = false;
|
|
constructor() {
|
|
super();
|
|
}
|
|
connectedCallback() {
|
|
this.container = document.createElement('pre');
|
|
this.container.classList.add('shiki-magic-move-container');
|
|
this.container.className += ` ${this.class}`;
|
|
this.renderer = new MagicMoveRenderer(this.container);
|
|
this.renderer.render(this.tokens);
|
|
this.appendChild(this.container);
|
|
}
|
|
propertyChangedCallback() {
|
|
if (!this.batchUpdate) {
|
|
this.batchUpdate = true;
|
|
setTimeout(() => {
|
|
this.batchUpdate = false;
|
|
if (!this.hasUpdated) {
|
|
this.hasUpdated = true;
|
|
return;
|
|
}
|
|
if (this.renderer) this.transform();
|
|
}, 0);
|
|
}
|
|
}
|
|
async transform() {
|
|
if (!this.renderer) return;
|
|
if (!this.animated) return;
|
|
if (this.previous && this.previous === this.tokens) return;
|
|
if (this.previous) {
|
|
this.renderer.replace(this.previous);
|
|
this.dispatchEvent(new CustomEvent('onStart'));
|
|
await this.renderer?.render(this.tokens);
|
|
this.dispatchEvent(new CustomEvent('onEnd'));
|
|
} else {
|
|
this.renderer.replace(this.tokens);
|
|
}
|
|
}
|
|
}
|
|
customElements.define('shiki-magic-move-renderer', ShikiMagicMoveRenderer);
|
|
|
|
class ShikiMagicMove extends HTMLElement {
|
|
get highlighter() {
|
|
return this._highlighter;
|
|
}
|
|
set highlighter(value) {
|
|
this._highlighter = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get lang() {
|
|
return this._lang;
|
|
}
|
|
set lang(value) {
|
|
this._lang = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get theme() {
|
|
return this._theme;
|
|
}
|
|
set theme(value) {
|
|
this._theme = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get code() {
|
|
return this._code;
|
|
}
|
|
set code(value) {
|
|
this._code = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get class() {
|
|
return this._class;
|
|
}
|
|
set class(value) {
|
|
this._class = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get options() {
|
|
return this._options;
|
|
}
|
|
set options(value) {
|
|
this._options = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
batchUpdate = false;
|
|
hasUpdated = false;
|
|
constructor() {
|
|
super();
|
|
}
|
|
connectedCallback() {
|
|
this.renderer = document.createElement('shiki-magic-move-renderer');
|
|
this.renderer.addEventListener('onStart', () => this.dispatchEvent(new CustomEvent('onStart')));
|
|
this.renderer.addEventListener('onEnd', () => this.dispatchEvent(new CustomEvent('onEnd')));
|
|
this.machine = createMagicMoveMachine(code => codeToKeyedTokens(this.highlighter, code, {
|
|
lang: this.lang,
|
|
theme: this.theme
|
|
}, this.options?.lineNumbers), this.options);
|
|
this.updateRenderer();
|
|
this.appendChild(this.renderer);
|
|
}
|
|
propertyChangedCallback() {
|
|
if (!this.batchUpdate) {
|
|
this.batchUpdate = true;
|
|
setTimeout(() => {
|
|
this.batchUpdate = false;
|
|
if (!this.hasUpdated) {
|
|
this.hasUpdated = true;
|
|
return;
|
|
}
|
|
this.updateRenderer();
|
|
}, 0);
|
|
}
|
|
}
|
|
updateRenderer() {
|
|
if (this.machine && this.renderer) {
|
|
this.result = this.machine.commit(this.code, this.options);
|
|
this.renderer.tokens = this.result.current;
|
|
this.renderer.previous = this.result.previous;
|
|
this.renderer.options = this.options;
|
|
this.renderer.class = this.class ?? '';
|
|
}
|
|
}
|
|
}
|
|
customElements.define('shiki-magic-move', ShikiMagicMove);
|
|
|
|
class ShikiMagicMovePrecompiled extends HTMLElement {
|
|
_steps = [];
|
|
_step = 0;
|
|
_animated = true;
|
|
get steps() {
|
|
return this._steps;
|
|
}
|
|
set steps(value) {
|
|
this._steps = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get step() {
|
|
return this._step;
|
|
}
|
|
set step(value) {
|
|
this._step = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get animated() {
|
|
return this._animated;
|
|
}
|
|
set animated(value) {
|
|
this._animated = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
get options() {
|
|
return this._options;
|
|
}
|
|
set options(value) {
|
|
this._options = value;
|
|
this.propertyChangedCallback();
|
|
}
|
|
previous = toKeyedTokens('', []);
|
|
batchUpdate = false;
|
|
hasUpdated = false;
|
|
constructor() {
|
|
super();
|
|
}
|
|
connectedCallback() {
|
|
this.renderer = document.createElement('shiki-magic-move-renderer');
|
|
this.renderer.addEventListener('onStart', () => this.dispatchEvent(new CustomEvent('onStart')));
|
|
this.renderer.addEventListener('onEnd', () => this.dispatchEvent(new CustomEvent('onEnd')));
|
|
this.updateRenderer();
|
|
this.appendChild(this.renderer);
|
|
}
|
|
propertyChangedCallback() {
|
|
if (!this.batchUpdate) {
|
|
this.batchUpdate = true;
|
|
setTimeout(() => {
|
|
this.batchUpdate = false;
|
|
if (!this.hasUpdated) {
|
|
this.hasUpdated = true;
|
|
return;
|
|
}
|
|
this.updateRenderer();
|
|
}, 0);
|
|
}
|
|
}
|
|
updateRenderer() {
|
|
const result = syncTokenKeys(this.previous, this.steps[Math.min(this.step, this.steps.length - 1)], this.options);
|
|
this.previous = result.to;
|
|
this.renderer.tokens = result.to;
|
|
this.renderer.previous = result.from;
|
|
this.renderer.options = this.options;
|
|
this.renderer.animated = this.animated;
|
|
}
|
|
}
|
|
customElements.define('shiki-magic-move-precompiled', ShikiMagicMovePrecompiled);
|
|
|
|
export { ShikiMagicMove, ShikiMagicMovePrecompiled, ShikiMagicMoveRenderer };
|