Comparing version 3.0.0 to 3.1.0
declare module '*.css'; |
@@ -9,3 +9,3 @@ export { default as CartaEditor } from './CartaEditor.svelte'; | ||
export * from './internal/highlight'; | ||
export * from './default-theme.css?inline'; | ||
export * from './default.css?inline'; | ||
export * from './light.css?inline'; |
@@ -5,3 +5,3 @@ export { default as CartaEditor } from './CartaEditor.svelte'; | ||
export * from './internal/highlight'; | ||
export * from './default-theme.css?inline'; | ||
export * from './default.css?inline'; | ||
export * from './light.css?inline'; |
@@ -0,3 +1,5 @@ | ||
import type { CartaHistoryOptions } from './history'; | ||
import type { SvelteComponentTyped } from 'svelte'; | ||
import type { ShjLanguageDefinition } from '@speed-highlight/core/index'; | ||
import { Marked, type MarkedExtension } from 'marked'; | ||
import type { CartaHistoryOptions } from './history'; | ||
import { CartaInput } from './input'; | ||
@@ -7,13 +9,5 @@ import { type DefaultShortcutId, type KeyboardShortcut } from './shortcuts'; | ||
import { type DefaultPrefixId, type Prefix } from './prefixes'; | ||
import type { SvelteComponentTyped } from 'svelte'; | ||
import { CartaRenderer } from './renderer'; | ||
import { type HighlightFunctions } from './highlight.js'; | ||
import type { ShjLanguageDefinition } from '@speed-highlight/core/index'; | ||
import { type GfmHeadingIdOptions } from 'marked-gfm-heading-id'; | ||
declare class CustomEvent<T> extends Event { | ||
detail: T; | ||
constructor(message: string, data: EventInit & { | ||
detail: T; | ||
}); | ||
} | ||
import { CustomEvent } from './utils'; | ||
/** | ||
@@ -84,12 +78,2 @@ * Carta-specific event with extra payload. | ||
sanitizer?: (html: string) => string; | ||
/** | ||
* marked-mangle. | ||
* @default true | ||
*/ | ||
mangle?: false; | ||
/** | ||
* marked-gfm-heading-ids options. | ||
* Use `false` to disable it. | ||
*/ | ||
gfmHeadingId?: GfmHeadingIdOptions | false; | ||
} | ||
@@ -162,6 +146,9 @@ /** | ||
readonly markedSync: Marked; | ||
private _element; | ||
private _input; | ||
private _renderer; | ||
get element(): HTMLDivElement | undefined; | ||
get input(): CartaInput | undefined; | ||
get renderer(): CartaRenderer | undefined; | ||
private elementsToBind; | ||
constructor(options?: CartaOptions | undefined); | ||
@@ -182,2 +169,7 @@ private useMarkedExtension; | ||
/** | ||
* **Internal**: set the editor element. | ||
* @param element The editor element. | ||
*/ | ||
$setElement(element: HTMLDivElement): void; | ||
/** | ||
* **Internal**: set the input element. | ||
@@ -193,3 +185,24 @@ * @param textarea The input textarea element. | ||
$setRenderer(container: HTMLDivElement): void; | ||
/** | ||
* Bind an element to the caret position. | ||
* @param element The element to bind. | ||
* @param portal The portal element. | ||
* @returns The unbind function. | ||
* | ||
* @example | ||
* ```svelte | ||
* <script> | ||
* export let carta; | ||
* </script> | ||
* | ||
* <div use:carta.bindToCaret> | ||
* <!-- Stuff here --> | ||
* </div> | ||
* | ||
* ``` | ||
*/ | ||
bindToCaret(element: HTMLElement, portal?: HTMLBodyElement): { | ||
destroy: () => void; | ||
}; | ||
} | ||
export {}; |
@@ -7,14 +7,4 @@ import { Marked } from 'marked'; | ||
import { CartaRenderer } from './renderer'; | ||
import { loadCustomLanguage, highlight, highlightAutodetect } from './highlight.js'; | ||
import { mangle } from 'marked-mangle'; | ||
import { gfmHeadingId } from 'marked-gfm-heading-id'; | ||
// Node does not implement CustomEvent until v19, so we | ||
// "declare" it ourself for backward compatibility. | ||
class CustomEvent extends Event { | ||
detail; | ||
constructor(message, data) { | ||
super(message, data); | ||
this.detail = data.detail; | ||
} | ||
} | ||
import { loadCustomLanguage, highlight, highlightAutodetect, loadCustomMarkdown } from './highlight.js'; | ||
import { CustomEvent } from './utils'; | ||
const cartaEvents = ['carta-render', 'carta-render-ssr']; | ||
@@ -33,4 +23,8 @@ export class Carta { | ||
markedSync = new Marked(); | ||
_element; | ||
_input; | ||
_renderer; | ||
get element() { | ||
return this._element; | ||
} | ||
get input() { | ||
@@ -42,2 +36,3 @@ return this._input; | ||
} | ||
elementsToBind = []; | ||
constructor(options) { | ||
@@ -73,18 +68,5 @@ this.options = options; | ||
// Load default icons | ||
this.icons.push(...defaultIcons.filter((icon) => options?.disableIcons === true ? false : !options?.disableIcons?.includes(icon.id))); | ||
this.icons.unshift(...defaultIcons.filter((icon) => options?.disableIcons === true ? false : !options?.disableIcons?.includes(icon.id))); | ||
// Load default prefixes | ||
this.prefixes.push(...defaultPrefixes.filter((prefix) => options?.disablePrefixes === true ? false : !options?.disablePrefixes?.includes(prefix.id))); | ||
// Load default marked extensions | ||
if (options?.mangle !== false) { | ||
this.useMarkedExtension(mangle()); | ||
} | ||
else { | ||
this.useMarkedExtension({ mangle: false }); | ||
} | ||
if (options?.gfmHeadingId !== false) { | ||
this.useMarkedExtension(gfmHeadingId(options?.gfmHeadingId)); | ||
} | ||
else { | ||
this.useMarkedExtension({ headerIds: false }); | ||
} | ||
// Load marked extensions | ||
@@ -99,8 +81,3 @@ const markedExtensions = this.options?.extensions | ||
// Load highlight custom language | ||
import('./shj.js') | ||
.then((module) => { | ||
// inject custom rules | ||
module.default.unshift(...this.highlightRules); | ||
return loadCustomLanguage('cartamd', module); | ||
}) | ||
loadCustomMarkdown(this.options?.extensions ?? []) | ||
// trigger re-render | ||
@@ -159,2 +136,9 @@ .then(() => this.input?.update()); | ||
/** | ||
* **Internal**: set the editor element. | ||
* @param element The editor element. | ||
*/ | ||
$setElement(element) { | ||
this._element = element; | ||
} | ||
/** | ||
* **Internal**: set the input element. | ||
@@ -165,2 +149,4 @@ * @param textarea The input textarea element. | ||
$setInput(textarea, container, callback) { | ||
// Remove old listeners if any | ||
this.input?.events.removeEventListener('update', callback); | ||
this._input = new CartaInput(textarea, container, { | ||
@@ -170,5 +156,10 @@ shortcuts: this.keyboardShortcuts, | ||
listeners: this.textareaListeners, | ||
callback: callback, | ||
historyOpts: this.options?.historyOptions | ||
}); | ||
this._input.events.addEventListener('update', callback); | ||
// Bind elements | ||
this.elementsToBind.forEach((it) => { | ||
it.callback = this.input?.$bindToCaret(it.elem, it.portal).destroy; | ||
}); | ||
this.elementsToBind = []; | ||
} | ||
@@ -182,2 +173,37 @@ /** | ||
} | ||
/** | ||
* Bind an element to the caret position. | ||
* @param element The element to bind. | ||
* @param portal The portal element. | ||
* @returns The unbind function. | ||
* | ||
* @example | ||
* ```svelte | ||
* <script> | ||
* export let carta; | ||
* </script> | ||
* | ||
* <div use:carta.bindToCaret> | ||
* <!-- Stuff here --> | ||
* </div> | ||
* | ||
* ``` | ||
*/ | ||
bindToCaret(element, portal = document.querySelector('body')) { | ||
if (this.input) { | ||
return this.input.$bindToCaret(element, portal); | ||
} | ||
else { | ||
let callback; | ||
// Bind the element later, when the input is ready | ||
this.elementsToBind.push({ elem: element, portal, callback }); | ||
return { | ||
destroy() { | ||
if (callback) { | ||
callback(); | ||
} | ||
} | ||
}; | ||
} | ||
} | ||
} |
@@ -1,2 +0,7 @@ | ||
import { type ShjLanguageDefinition } from '@speed-highlight/core'; | ||
import { type ShjLanguage, type ShjLanguageDefinition } from '@speed-highlight/core'; | ||
import type { CartaExtension } from './carta'; | ||
interface Nothing { | ||
} | ||
type Union<T, U> = T | (U & Nothing); | ||
type Lang = Union<ShjLanguage, string>; | ||
/** | ||
@@ -10,3 +15,3 @@ * Highlight text using Speed-Highlight. May return null on error(usually if requested | ||
*/ | ||
export declare function highlight(text: string, lang: string, hideLineNumbers?: boolean): Promise<string | null>; | ||
export declare function highlight(text: string, lang: Lang, hideLineNumbers?: boolean): Promise<string | null>; | ||
/** | ||
@@ -49,1 +54,8 @@ * Highlight text using Speed-Highlight with detected language. | ||
} | ||
/** | ||
* Load custom markdown syntax highlighting rules. | ||
* Automatically called when a Carta instance is created. | ||
* @param extensions Additional extensions used in Carta. | ||
*/ | ||
export declare function loadCustomMarkdown(extensions?: CartaExtension[]): Promise<void>; | ||
export {}; |
import { detectLanguage } from '@speed-highlight/core/detect.js'; | ||
import { highlightText, loadLanguage } from '@speed-highlight/core'; | ||
import cartaMarkdown from './shj'; | ||
/** | ||
@@ -54,1 +55,11 @@ * Highlight text using Speed-Highlight. May return null on error(usually if requested | ||
} | ||
/** | ||
* Load custom markdown syntax highlighting rules. | ||
* Automatically called when a Carta instance is created. | ||
* @param extensions Additional extensions used in Carta. | ||
*/ | ||
export async function loadCustomMarkdown(extensions = []) { | ||
const highlightRules = extensions.map((ext) => ext.highlightRules ?? []).flat(); | ||
const lang = Array.prototype.concat(cartaMarkdown, highlightRules); | ||
loadCustomLanguage('cartamd', { default: lang }); | ||
} |
import type { CartaListener } from './carta'; | ||
import { CartaHistory, type CartaHistoryOptions } from './history'; | ||
import type { Prefix } from './prefixes'; | ||
import type { KeyboardShortcut } from './shortcuts'; | ||
import { CartaHistory, type CartaHistoryOptions } from './history'; | ||
/** | ||
@@ -21,3 +21,2 @@ * Text selection information. | ||
readonly listeners: CartaListener<any>[]; | ||
readonly callback: () => void; | ||
readonly historyOpts?: Partial<CartaHistoryOptions>; | ||
@@ -30,4 +29,5 @@ } | ||
private pressedKeys; | ||
private onKeyDownValue; | ||
readonly history: CartaHistory; | ||
private onKeyDownValue; | ||
readonly events: EventTarget; | ||
constructor(textarea: HTMLTextAreaElement, container: HTMLDivElement, settings: InputSettings); | ||
@@ -79,3 +79,3 @@ private isWordCharacter; | ||
*/ | ||
update: () => void; | ||
update: () => boolean; | ||
/** | ||
@@ -96,3 +96,3 @@ * Returns x, y coordinates for absolute positioning of a span within a given text input | ||
* Moves an element next to the caret. Shall be called every time the element | ||
* changes width, height or the caret position changes. | ||
* changes width, height or the caret position changes. Consider using `bindToCaret` instead. | ||
* | ||
@@ -136,2 +136,11 @@ * @example | ||
/** | ||
* **Internal**: Svelte action to bind an element to the caret position. | ||
* Use `bindToCaret` from the `carta` instance instead. | ||
* @param elem The element to position. | ||
* @param portal The portal to append the element to. Defaults to `document.body`. | ||
*/ | ||
$bindToCaret(elem: HTMLElement, portal: HTMLElement): { | ||
destroy: () => void; | ||
}; | ||
/** | ||
* Get rough value for a row of the textarea. | ||
@@ -138,0 +147,0 @@ */ |
@@ -8,5 +8,6 @@ import { CartaHistory } from './history'; | ||
pressedKeys; | ||
history; | ||
// Used to detect keys that actually changed the textarea value | ||
onKeyDownValue; | ||
history; | ||
events = new EventTarget(); | ||
constructor(textarea, container, settings) { | ||
@@ -72,3 +73,3 @@ this.textarea = textarea; | ||
this.history.saveState(this.textarea.value, this.textarea.selectionStart); | ||
this.settings.callback(); | ||
this.update(); | ||
} | ||
@@ -119,3 +120,3 @@ this.onKeyDownValue = undefined; | ||
this.textarea.setSelectionRange(line.start, line.start); | ||
this.settings.callback(); | ||
this.update(); | ||
return; | ||
@@ -125,3 +126,3 @@ } | ||
this.insertAt(cursor, '\n' + newPrefix); | ||
this.settings.callback(); | ||
this.update(); | ||
// Update cursor position | ||
@@ -244,3 +245,3 @@ const newCursorPosition = cursor + newPrefix.length + 1; | ||
*/ | ||
update = () => this.settings.callback(); | ||
update = () => this.events.dispatchEvent(new Event('update')); | ||
/** | ||
@@ -288,3 +289,3 @@ * Returns x, y coordinates for absolute positioning of a span within a given text input | ||
* Moves an element next to the caret. Shall be called every time the element | ||
* changes width, height or the caret position changes. | ||
* changes width, height or the caret position changes. Consider using `bindToCaret` instead. | ||
* | ||
@@ -353,2 +354,57 @@ * @example | ||
/** | ||
* **Internal**: Svelte action to bind an element to the caret position. | ||
* Use `bindToCaret` from the `carta` instance instead. | ||
* @param elem The element to position. | ||
* @param portal The portal to append the element to. Defaults to `document.body`. | ||
*/ | ||
$bindToCaret(elem, portal) { | ||
// Move the element to body | ||
portal.appendChild(elem); | ||
elem.style.position = 'absolute'; | ||
const callback = () => { | ||
const relativePosition = this.getCursorXY(); | ||
const absolutePosition = { | ||
x: relativePosition.x + this.textarea.getBoundingClientRect().left, | ||
y: relativePosition.y + this.textarea.getBoundingClientRect().top | ||
}; | ||
const fontSize = this.getRowHeight(); | ||
const width = elem.clientWidth; | ||
const height = elem.clientHeight; | ||
// Left/Right | ||
let left = absolutePosition.x; | ||
let right; | ||
if (left + width >= window.innerWidth) { | ||
right = window.innerWidth - left; | ||
left = undefined; | ||
} | ||
// Top/Bottom | ||
let top = absolutePosition.y; | ||
let bottom; | ||
if (top + height >= window.innerHeight) { | ||
bottom = window.innerHeight - top; | ||
top = undefined; | ||
} | ||
elem.style.left = left !== undefined ? left + 'px' : 'unset'; | ||
elem.style.right = right !== undefined ? right + 'px' : 'unset'; | ||
elem.style.top = top !== undefined ? top + fontSize + 'px' : 'unset'; | ||
elem.style.bottom = bottom !== undefined ? bottom + 'px' : 'unset'; | ||
}; | ||
this.textarea.addEventListener('input', callback); | ||
window.addEventListener('resize', callback); | ||
// Initial positioning | ||
callback(); | ||
return { | ||
destroy: () => { | ||
try { | ||
portal.removeChild(elem); | ||
} | ||
catch (e) { | ||
// Ignore | ||
} | ||
this.textarea.removeEventListener('input', callback); | ||
window.removeEventListener('resize', callback); | ||
} | ||
}; | ||
} | ||
/** | ||
* Get rough value for a row of the textarea. | ||
@@ -355,0 +411,0 @@ */ |
@@ -21,1 +21,7 @@ /** | ||
export declare function mergeDefaultInterface<T extends object>(partial: Partial<T> | undefined, def: T): T; | ||
export declare class CustomEvent<T> extends Event { | ||
detail: T; | ||
constructor(message: string, data: EventInit & { | ||
detail: T; | ||
}); | ||
} |
@@ -51,1 +51,10 @@ /** | ||
} | ||
// Node does not implement CustomEvent until v19, so we | ||
// "declare" it ourself for backward compatibility. | ||
export class CustomEvent extends Event { | ||
detail; | ||
constructor(message, data) { | ||
super(message, data); | ||
this.detail = data.detail; | ||
} | ||
} |
@@ -9,3 +9,3 @@ { | ||
"type": "git", | ||
"url": "https://github.com/BearToCode/carta-md.git" | ||
"url": "git+https://github.com/BearToCode/carta.git" | ||
}, | ||
@@ -18,7 +18,8 @@ "exports": { | ||
}, | ||
"./default-theme.css": "./dist/default-theme.css", | ||
"./default.css": "./dist/default.css", | ||
"./default-theme.css": "./dist/default.css", | ||
"./light.css": "./dist/light.css", | ||
"./dark.css": "./dist/dark.css" | ||
}, | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"scripts": { | ||
@@ -25,0 +26,0 @@ "dev": "vite dev", |
@@ -10,4 +10,4 @@ <div align="center"> | ||
<a href="https://bundlephobia.com/package/carta-md"><img src="https://img.shields.io/bundlephobia/min/carta-md?color=16b57c&labelColor=171d27&logo=javascript&logoColor=white" alt="bundle"></a> | ||
<a href="https://github.com/BearToCode/carta-md/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/carta-md?color=16b57c&labelColor=171d27&logo=git&logoColor=white" alt="license"></a> | ||
<a href="http://beartocode.github.io/carta-md/"><img src="https://img.shields.io/badge/available-red?label=demo&color=16b57c&labelColor=171d27&logo=svelte&logoColor=white" alt="demo"></a> | ||
<a href="https://github.com/BearToCode/carta/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/carta-md?color=16b57c&labelColor=171d27&logo=git&logoColor=white" alt="license"></a> | ||
<a href="http://beartocode.github.io/carta/"><img src="https://img.shields.io/badge/available-red?label=demo&color=16b57c&labelColor=171d27&logo=svelte&logoColor=white" alt="demo"></a> | ||
</div> | ||
@@ -17,3 +17,3 @@ | ||
Carta is a **lightweight**, **fast** and **extensible** Svelte Markdown editor and viewer, based on [Marked](https://github.com/markedjs/marked). Check out the [demo](http://beartocode.github.io/carta-md/) to see it in action. | ||
Carta is a **lightweight**, **fast** and **extensible** Svelte Markdown editor and viewer, based on [Marked](https://github.com/markedjs/marked). Check out the [demo](http://beartocode.github.io/carta/) to see it in action. | ||
Differently from most editors, Carta includes neither ProseMirror nor CodeMirror, allowing for an extremely small bundle size and fast loading time. | ||
@@ -61,3 +61,3 @@ | ||
// Component default theme | ||
import 'carta-md/default-theme.css'; | ||
import 'carta-md/default.css'; | ||
// Markdown input theme (Speed Highlight) | ||
@@ -98,10 +98,10 @@ import 'carta-md/light.css'; | ||
| Name | Description | | ||
| -------------------------------------------------------------------------------------------------- | --------------------------------------- | | ||
| [plugin-math](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-math) | Katex support | | ||
| [plugin-slash](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-slash) | Slash commands support | | ||
| [plugin-emoji](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-emoji) | Emojis support, including inline search | | ||
| [plugin-code](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-code) | Code blocks syntax highlighting | | ||
| [plugin-tikz](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-tikz) | TikZ support using TikZJax | | ||
| [plugin-attachment](https://github.com/BearToCode/carta-md/tree/master/packages/plugin-attachment) | Attachments support | | ||
| Name | Description | | ||
| ----------------------------------------------------------------------------------------------- | --------------------------------------- | | ||
| [plugin-math](https://github.com/BearToCode/carta/tree/master/packages/plugin-math) | Katex support | | ||
| [plugin-slash](https://github.com/BearToCode/carta/tree/master/packages/plugin-slash) | Slash commands support | | ||
| [plugin-emoji](https://github.com/BearToCode/carta/tree/master/packages/plugin-emoji) | Emojis support, including inline search | | ||
| [plugin-code](https://github.com/BearToCode/carta/tree/master/packages/plugin-code) | Code blocks syntax highlighting | | ||
| [plugin-tikz](https://github.com/BearToCode/carta/tree/master/packages/plugin-tikz) | TikZ support using TikZJax | | ||
| [plugin-attachment](https://github.com/BearToCode/carta/tree/master/packages/plugin-attachment) | Attachments support | | ||
@@ -112,3 +112,3 @@ ## Themes customization | ||
Check out the [default theme](https://github.com/BearToCode/carta-md/blob/master/packages/carta-md/src/lib/default-theme.css) to customize it. | ||
Check out the [default theme](https://github.com/BearToCode/carta/blob/master/packages/carta-md/src/lib/default.css) to customize it. | ||
@@ -115,0 +115,0 @@ If you are using a plugin, look at its _readme_ for its customization. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97019
2239