Security News
Opengrep Emerges as Open Source Alternative Amid Semgrep Licensing Controversy
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
A beautiful, modern, customizable Markdown editor powered by CodeMirror 6 and TypeScript.
A beautiful, modern, customizable Markdown editor powered by CodeMirror 6 and TypeScript. This is the editor that powers https://octo.app.
ink-mde/vue
subpath export)ink-mde/svelte
subpath export)textarea
element with the wrap
exportWith your preferred package manager, add ink-mde
to your project.
# npm
npm i ink-mde
# pnpm
pnpm i ink-mde
# yarn
yarn add ink-mde
The officially supported CDN for ink-mde
is esm.sh. Visit esm.sh/ink-mde and you will be redirected to the latest version. The URL will look something like this.
https://esm.sh/ink-mde@0.22.0
Then, import ink
from that URL in your project.
import { ink } from 'https://esm.sh/ink-mde@0.22.0'
ink-mde
Next, import ink-mde
and customize it to fit your needs.
Mount the component and start writing.
// ./examples/minimal.ts
import { ink } from 'ink-mde'
// The only requirement is an HTML element.
ink(document.getElementById('editor')!)
textarea
with wrap
To wrap a native textarea
element, use the wrap
export.
import { wrap } from 'ink-mde'
wrap(document.querySelector('textarea')!)
To sync the editor with your app's state, you can use the afterUpdate
hook.
// ./examples/hooks.ts
import { defineOptions, ink } from 'ink-mde'
// With hooks, you can keep your state in sync with the editor.
const state = { doc: '# Start with some text' }
// Use defineOptions for automatic type hinting.
const options = defineOptions({
doc: state.doc,
hooks: {
afterUpdate: (doc: string) => {
state.doc = doc
},
},
})
const editor = ink(document.getElementById('editor')!, options)
// You can also update the editor directly.
editor.update(state.doc)
// ./examples/web-component.ts#L1-L16
import { ink } from 'ink-mde'
import { LitElement, html } from 'lit'
class InkMde extends LitElement {
firstUpdated() {
ink(this.renderRoot.querySelector('#editor')!, {
doc: '# Hello, World!',
})
}
render() {
return html`<div id="editor"></div>`
}
}
customElements.define('ink-mde', InkMde)
ink-mde/vue
The ink-mde/vue
subpath exports a Vue 3 component.
<script lang="ts" setup>
import InkMde from 'ink-mde/vue'
import { ref } from 'vue'
const markdown = ref('# Hello, World!')
</script>
<template>
<InkMde v-model="markdown" />
</template>
The Vue component forwards all options that ink-mde
supports, and it uses a deep watcher to ensure your options
are reactive.
<script lang="ts" setup>
import InkMde from 'ink-mde/vue'
import { reactive, ref } from 'vue'
const markdown = ref('# Hello, World!')
const options = reactive({
interface: {
appearance: 'dark',
},
})
</script>
<template>
<input v-model="options.interface.appearance" type="radio" value="dark"> dark
<input v-model="options.interface.appearance" type="radio" value="light"> light
<InkMde v-model="markdown" :options="options" />
</template>
ink-mde/svelte
The ink-mde/svelte
subpath exports a Svelte component.
<script lang="ts">
import InkMde from 'ink-mde/svelte'
// doc
let value = '# Hello, world'
</script>
<InkMde
bind:value
options={{
interface: {
appearance: 'dark'
}
}}
/>
<script lang="ts">
import InkMde from 'ink-mde/svelte'
import type { Instance } from 'ink-mde'
// doc
let value = '# Hello, world'
// reactive option, if this change, the editor will be reconfigured.
let isDarkTheme = false
</script>
<input type="checkbox" bind:checked={isDarkTheme} name="isDarkTheme" />
<InkMde
bind:value
options={{
interface: {
appearance: isDarkTheme ? 'dark' : 'light',
},
}}
/>
These are the default options, and any of them can be overridden when initializing (or reconfiguring) an instance of ink-mde
.
// ./src/store.ts#L12-L66
const options = {
doc: '',
files: {
clipboard: false,
dragAndDrop: false,
handler: () => {},
injectMarkup: true,
types: ['image/*'],
},
hooks: {
afterUpdate: () => {},
beforeUpdate: () => {},
},
interface: {
appearance: InkValues.Appearance.Auto,
attribution: true,
autocomplete: false,
images: false,
lists: false,
readonly: false,
spellcheck: true,
toolbar: false,
},
katex: false,
keybindings: {
// Todo: Set these to false by default. https://codemirror.net/examples/tab
tab: true,
shiftTab: true,
},
lists: false,
placeholder: '',
plugins: [
katex(),
],
readability: false,
search: true,
selections: [],
toolbar: {
bold: true,
code: true,
codeBlock: true,
heading: true,
image: true,
italic: true,
link: true,
list: true,
orderedList: true,
quote: true,
taskList: true,
upload: false,
},
// This value overrides both `tab` and `shiftTab` keybindings.
trapTab: undefined,
vim: false,
}
The editor can be extended with custom grammars, completions, and more through the Plugin API. Examples coming soon.
Many aspects of the editor's appearance can be customized with CSS custom properties (aka CSS variables).
CSS Custom Property | CSS Property | Default (Dark) | Override (Light) |
---|---|---|---|
--ink-border-radius | border-radius | 0.25rem | |
--ink-color | color | #fafafa | #171717 |
--ink-font-family | font-family | sans-serif | |
--ink-flex-direction | flex-direction | column |
Blocks are used to provide a dynamic user experience. Examples of blocks are images, multiline code blocks, and the toolbar.
CSS Custom Property | CSS Property | Default (Dark) | Override (Light) |
---|---|---|---|
--ink-block-background-color | background-color | #121212 | #f5f5f5 |
--ink-block-background-color-on-hover | background-color | #0f0f0f | #e0e0e0 |
--ink-block-max-height | max-height | 20rem | |
--ink-block-padding | padding | 0.5rem |
These styles are for code blocks and inline code.
CSS Custom Property | CSS Property | Default (Dark) | Override (Light) |
---|---|---|---|
--ink-code-background-color | background-color | var(--ink-block-background-color) | |
--ink-code-color | color | inherit | |
--ink-code-font-family | font-family | 'Monaco', Courier, monospace |
You can customize the entire syntax theme too.
CSS Custom Property | CSS Property | Default (Dark) | Override (Light) |
---|---|---|---|
--ink-syntax-atom-color | color | #d19a66 | |
--ink-syntax-comment-color | color | #abb2bf | |
--ink-syntax-emphasis-color | color | inherit | |
--ink-syntax-emphasis-font-style | font-style | italic | |
--ink-syntax-heading-color | color | #e06c75 | |
--ink-syntax-heading-font-size | font-size | 1em | |
--ink-syntax-heading-font-weight | font-weight | 600 | |
--ink-syntax-heading1-color | color | #e06c75 | |
--ink-syntax-heading1-font-size | font-size | 1.6em | |
--ink-syntax-heading1-font-weight | font-weight | 600 | |
--ink-syntax-heading2-color | color | #e06c75 | |
--ink-syntax-heading2-font-size | font-size | 1.5em | |
--ink-syntax-heading2-font-weight | font-weight | 600 | |
--ink-syntax-heading3-color | color | #e06c75 | |
--ink-syntax-heading3-font-size | font-size | 1.4em | |
--ink-syntax-heading3-font-weight | font-weight | 600 | |
--ink-syntax-heading4-color | color | #e06c75 | |
--ink-syntax-heading4-font-size | font-size | 1.3em | |
--ink-syntax-heading4-font-weight | font-weight | 600 | |
--ink-syntax-heading5-color | color | #e06c75 | |
--ink-syntax-heading5-font-size | font-size | 1.2em | |
--ink-syntax-heading5-font-weight | font-weight | 600 | |
--ink-syntax-heading6-color | color | #e06c75 | |
--ink-syntax-heading6-font-size | font-size | 1.1em | |
--ink-syntax-heading6-font-weight | font-weight | 600 | |
--ink-syntax-keyword-color | color | #c678dd | |
--ink-syntax-link-color | color | #96c0d8 | |
--ink-syntax-meta-color | color | #abb2bf | |
--ink-syntax-name-color | color | #d19a66 | |
--ink-syntax-name-label-color | color | #abb2bf | |
--ink-syntax-name-property-color | color | #96c0d8 | |
--ink-syntax-name-property-definition-color | color | #e06c75 | |
--ink-syntax-name-variable-color | color | #e06c75 | |
--ink-syntax-name-variable-definition-color | color | #e5c07b | |
--ink-syntax-name-variable-local-color | color | #d19a66 | |
--ink-syntax-name-variable-special-color | color | inherit | |
--ink-syntax-number-color | color | #d19a66 | |
--ink-syntax-operator-color | color | #96c0d8 | |
--ink-syntax-processing-instruction-color | color | #444444 | #bbbbbb |
--ink-syntax-punctuation-color | color | #abb2bf | |
--ink-syntax-strikethrough-color | color | inherit | |
--ink-syntax-strikethrough-text-decoration | text-decoration | line-through | |
--ink-syntax-string-color | color | #98c379 | |
--ink-syntax-string-special-color | color | inherit | |
--ink-syntax-strong-color | color | inherit | |
--ink-syntax-strong-font-weight | font-weight | 600 | |
--ink-syntax-url-color | color | #aaaaaa | #666666 |
Your support is appreciated. Here are some ways you can help. ♥️
There is a small powered by ink-mde
attribution in the bottom-right corner of all editor instances by default. Being a free, MIT-licensed library under independent development, that attribution helps to increase awareness of this project and my work in general.
Your feedback is immensely important for building ink-mde
into a library that we all love. Consider starting a discussion under Octo if you have a question or just want to chat about ideas!
If you feel comfortable with an existing issue, please consider opening a Pull Request. I would love to work with you to get it merged!
Since ink-mde
is a v0 project, you should consider minor version increments to be breaking changes. Semantic Versioning considers all v0 releases to be breaking, but I do my best to make patch releases non-breaking.
FAQs
A beautiful, modern, customizable Markdown editor powered by CodeMirror 6 and TypeScript.
The npm package ink-mde receives a total of 677 weekly downloads. As such, ink-mde popularity was classified as not popular.
We found that ink-mde demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.