@milkdown/preset-commonmark
Advanced tools
Comparing version 5.5.0 to 6.0.0-next.0
@@ -1,1 +0,34 @@ | ||
export * from './src/index' | ||
import { AtomList } from '@milkdown/utils'; | ||
import { commonmarkPlugins } from './plugin'; | ||
export * from './mark'; | ||
export * from './node'; | ||
export * from './supported-keys'; | ||
export declare const commonmarkNodes: AtomList<(import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<"CodeFence", { | ||
languageList?: string[] | undefined; | ||
}>> & import("@milkdown/core").MilkdownPlugin) | (import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<string, import("./node").ImageOptions>> & import("@milkdown/core").MilkdownPlugin)>; | ||
export { commonmarkPlugins }; | ||
export declare const commonmark: AtomList<(import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<"CodeFence", { | ||
languageList?: string[] | undefined; | ||
}>> & import("@milkdown/core").MilkdownPlugin) | (import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<string, import("./node").ImageOptions>> & import("@milkdown/core").MilkdownPlugin)>; | ||
export declare const commands: { | ||
readonly ToggleInlineCode: import("@milkdown/core").CmdKey<undefined>; | ||
readonly ToggleItalic: import("@milkdown/core").CmdKey<undefined>; | ||
readonly ToggleLink: import("@milkdown/core").CmdKey<string>; | ||
readonly ToggleBold: import("@milkdown/core").CmdKey<undefined>; | ||
readonly ModifyLink: import("@milkdown/core").CmdKey<string>; | ||
readonly ModifyImage: import("@milkdown/core").CmdKey<string>; | ||
readonly WrapInBlockquote: import("@milkdown/core").CmdKey<undefined>; | ||
readonly WrapInBulletList: import("@milkdown/core").CmdKey<undefined>; | ||
readonly WrapInOrderedList: import("@milkdown/core").CmdKey<undefined>; | ||
readonly TurnIntoCodeFence: import("@milkdown/core").CmdKey<undefined>; | ||
readonly TurnIntoHeading: import("@milkdown/core").CmdKey<number>; | ||
readonly TurnIntoText: import("@milkdown/core").CmdKey<undefined>; | ||
readonly InsertHardbreak: import("@milkdown/core").CmdKey<undefined>; | ||
readonly InsertHr: import("@milkdown/core").CmdKey<string>; | ||
readonly InsertImage: import("@milkdown/core").CmdKey<string>; | ||
readonly SplitListItem: import("@milkdown/core").CmdKey<undefined>; | ||
readonly SinkListItem: import("@milkdown/core").CmdKey<undefined>; | ||
readonly LiftListItem: import("@milkdown/core").CmdKey<undefined>; | ||
}; | ||
export declare type Commands = typeof commands; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -7,3 +7,3 @@ var __defProp = Object.defineProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value; | ||
var __spreadValues = (a, b) => { | ||
@@ -22,4 +22,4 @@ for (var prop in b || (b = {})) | ||
import { createMark, createShortcut, createNode, createPlugin, AtomList } from "@milkdown/utils"; | ||
import { createCmdKey, createCmd, schemaCtx, themeToolCtx, editorViewCtx } from "@milkdown/core"; | ||
import { markRule, toggleMark, TextSelection, InputRule, wrappingInputRule, wrapIn, textblockTypeInputRule, setBlockType, Plugin, PluginKey, ReplaceStep, AddMarkStep, Selection, findSelectedNodeOfType, splitListItem, sinkListItem, liftListItem } from "@milkdown/prose"; | ||
import { createCmdKey, createCmd, schemaCtx, commandsCtx, editorViewCtx } from "@milkdown/core"; | ||
import { markRule, toggleMark, PluginKey, TextSelection, InputRule, Plugin, wrappingInputRule, wrapIn, textblockTypeInputRule, setBlockType, ReplaceStep, AddMarkStep, Selection, findSelectedNodeOfType, splitListItem, sinkListItem, liftListItem } from "@milkdown/prose"; | ||
import links from "remark-inline-links"; | ||
@@ -49,10 +49,2 @@ const SupportedKeys = { | ||
const codeInline = createMark((utils) => { | ||
const style = utils.getStyle(({ palette, size, font }, { css }) => css` | ||
background-color: ${palette("neutral")}; | ||
color: ${palette("background")}; | ||
border-radius: ${size.radius}; | ||
font-weight: 500; | ||
font-family: ${font.code}; | ||
padding: 0 0.2rem; | ||
`); | ||
return { | ||
@@ -65,3 +57,3 @@ id: id$a, | ||
parseDOM: [{ tag: "code" }], | ||
toDOM: (mark) => ["code", { class: utils.getClassName(mark.attrs, "code-inline", style) }], | ||
toDOM: (mark) => ["code", { class: utils.getClassName(mark.attrs, "code-inline") }], | ||
parseMarkdown: { | ||
@@ -124,19 +116,7 @@ match: (node) => node.type === "inlineCode", | ||
})); | ||
const key$1 = new PluginKey("MILKDOWN_PLUGIN_LINK_INPUT"); | ||
const ToggleLink = createCmdKey("ToggleLink"); | ||
const ModifyLink = createCmdKey("ModifyLink"); | ||
const id$8 = "link"; | ||
const link = createMark((utils) => { | ||
const style = utils.getStyle((themeTool, { css }) => { | ||
const lineColor = themeTool.palette("line"); | ||
return css` | ||
color: ${themeTool.palette("secondary")}; | ||
cursor: pointer; | ||
transition: all 0.4s ease-in-out; | ||
font-weight: 500; | ||
&:hover { | ||
background-color: ${lineColor}; | ||
box-shadow: 0 0.2rem ${lineColor}, 0 -0.2rem ${lineColor}; | ||
} | ||
`; | ||
}); | ||
const link = createMark((utils, options) => { | ||
return { | ||
@@ -161,3 +141,3 @@ id: id$8, | ||
], | ||
toDOM: (mark) => ["a", __spreadProps(__spreadValues({}, mark.attrs), { class: utils.getClassName(mark.attrs, id$8, style) })], | ||
toDOM: (mark) => ["a", __spreadProps(__spreadValues({}, mark.attrs), { class: utils.getClassName(mark.attrs, id$8) })], | ||
parseMarkdown: { | ||
@@ -223,3 +203,69 @@ match: (node) => node.type === "link", | ||
}) | ||
] | ||
], | ||
prosePlugins: (type, ctx) => { | ||
var _a, _b, _c; | ||
const inputChipRenderer = utils.themeManager.get("input-chip", { | ||
placeholder: (_b = (_a = options == null ? void 0 : options.input) == null ? void 0 : _a.placeholder) != null ? _b : "Input Web Link", | ||
buttonText: (_c = options == null ? void 0 : options.input) == null ? void 0 : _c.buttonText, | ||
onUpdate: (value) => { | ||
ctx.get(commandsCtx).call(ModifyLink, value); | ||
} | ||
}); | ||
const shouldDisplay = (view) => { | ||
const { selection, doc: doc2 } = view.state; | ||
const { from, to } = selection; | ||
return selection.empty && selection instanceof TextSelection && doc2.rangeHasMark(from, from === to ? to + 1 : to, type); | ||
}; | ||
const getCurrentLink = (view) => { | ||
const { selection } = view.state; | ||
let node; | ||
const { from, to } = selection; | ||
view.state.doc.nodesBetween(from, from === to ? to + 1 : to, (n) => { | ||
if (type.isInSet(n.marks)) { | ||
node = n; | ||
return false; | ||
} | ||
return; | ||
}); | ||
if (!node) | ||
return; | ||
const mark = node.marks.find((m) => m.type === type); | ||
if (!mark) | ||
return; | ||
const value = mark.attrs["href"]; | ||
return value; | ||
}; | ||
const renderByView = (view) => { | ||
if (!view.editable) { | ||
return; | ||
} | ||
const display = shouldDisplay(view); | ||
if (display) { | ||
inputChipRenderer.show(view); | ||
inputChipRenderer.update(getCurrentLink(view)); | ||
} else { | ||
inputChipRenderer.hide(); | ||
} | ||
}; | ||
return [ | ||
new Plugin({ | ||
key: key$1, | ||
view: (editorView) => { | ||
inputChipRenderer.init(editorView); | ||
renderByView(editorView); | ||
return { | ||
update: (view, prevState) => { | ||
const isEqualSelection = (prevState == null ? void 0 : prevState.doc.eq(view.state.doc)) && prevState.selection.eq(view.state.selection); | ||
if (isEqualSelection) | ||
return; | ||
renderByView(view); | ||
}, | ||
destroy: () => { | ||
inputChipRenderer.destroy(); | ||
} | ||
}; | ||
} | ||
}) | ||
]; | ||
} | ||
}; | ||
@@ -230,5 +276,2 @@ }); | ||
const strong = createMark((utils) => { | ||
const style = utils.getStyle((_, { css }) => css` | ||
font-weight: 600; | ||
`); | ||
return { | ||
@@ -242,3 +285,3 @@ id: id$7, | ||
], | ||
toDOM: (mark) => ["strong", { class: utils.getClassName(mark.attrs, id$7, style) }], | ||
toDOM: (mark) => ["strong", { class: utils.getClassName(mark.attrs, id$7) }], | ||
parseMarkdown: { | ||
@@ -273,11 +316,2 @@ match: (node) => node.type === "strong", | ||
const blockquote = createNode((utils) => { | ||
const style = utils.getStyle((themeTool, { css }) => css` | ||
padding-left: 1.875rem; | ||
line-height: 1.75rem; | ||
border-left: 4px solid ${themeTool.palette("primary")}; | ||
* { | ||
font-size: 1rem; | ||
line-height: 1.5rem; | ||
} | ||
`); | ||
return { | ||
@@ -290,3 +324,3 @@ id: id$6, | ||
parseDOM: [{ tag: "blockquote" }], | ||
toDOM: (node) => ["blockquote", { class: utils.getClassName(node.attrs, id$6, style) }, 0], | ||
toDOM: (node) => ["blockquote", { class: utils.getClassName(node.attrs, id$6) }, 0], | ||
parseMarkdown: { | ||
@@ -367,114 +401,6 @@ match: ({ type }) => type === id$6, | ||
const codeFence = createNode((utils, options) => { | ||
const style = utils.getStyle(({ palette, mixin, size, font }, { css }) => { | ||
const { shadow, scrollbar, border } = mixin; | ||
const { lineWidth, radius } = size; | ||
return css` | ||
background-color: ${palette("background")}; | ||
color: ${palette("neutral")}; | ||
font-size: 0.85rem; | ||
padding: 1.2rem 0.4rem 1.4rem; | ||
border-radius: ${radius}; | ||
font-family: ${font.typography}; | ||
* { | ||
margin: 0; | ||
} | ||
.code-fence_select-wrapper { | ||
position: relative; | ||
} | ||
.code-fence_value { | ||
width: 10.25rem; | ||
box-sizing: border-box; | ||
border-radius: ${size.radius}; | ||
margin: 0 1.2rem 1.2rem; | ||
${border()}; | ||
${shadow()}; | ||
cursor: pointer; | ||
background-color: ${palette("surface")}; | ||
position: relative; | ||
display: flex; | ||
color: ${palette("neutral", 0.87)}; | ||
letter-spacing: 0.5px; | ||
height: 2.625rem; | ||
align-items: center; | ||
& > .icon { | ||
width: 2.625rem; | ||
height: 100%; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
color: ${palette("solid", 0.87)}; | ||
border-left: ${lineWidth} solid ${palette("line")}; | ||
text-align: center; | ||
transition: all 0.2s ease-in-out; | ||
&:hover { | ||
background: ${palette("background")}; | ||
color: ${palette("primary")}; | ||
} | ||
} | ||
> span:first-child { | ||
padding-left: 1rem; | ||
flex: 1; | ||
font-weight: 500; | ||
} | ||
} | ||
.code-fence_select-option { | ||
list-style: none; | ||
line-height: 2rem; | ||
padding-left: 1rem; | ||
cursor: pointer; | ||
:hover { | ||
background: ${palette("secondary", 0.12)}; | ||
color: ${palette("primary")}; | ||
} | ||
} | ||
.code-fence_select { | ||
&[data-fold='true'] { | ||
display: none; | ||
} | ||
font-weight: 500; | ||
position: absolute; | ||
z-index: 1; | ||
top: 2.625rem; | ||
box-sizing: border-box; | ||
left: 1.2rem; | ||
padding: 0.5rem 0; | ||
max-height: 16.75rem; | ||
width: 10.25rem; | ||
${border()}; | ||
${shadow()}; | ||
background-color: ${palette("surface")}; | ||
border-top: none; | ||
overflow-y: auto; | ||
display: flex; | ||
flex-direction: column; | ||
${scrollbar("y")} | ||
} | ||
code { | ||
line-height: 1.5; | ||
font-family: ${font.code}; | ||
} | ||
pre { | ||
font-family: ${font.code}; | ||
margin: 0 1.2rem !important; | ||
white-space: pre; | ||
overflow: auto; | ||
${scrollbar("x")}; | ||
} | ||
`; | ||
}); | ||
const languageList = (options == null ? void 0 : options.languageList) || languageOptions; | ||
return { | ||
id: id$5, | ||
schema: () => ({ | ||
schema: (ctx) => ({ | ||
content: "text*", | ||
@@ -506,9 +432,45 @@ group: "block", | ||
toDOM: (node) => { | ||
const select = document.createElement("select"); | ||
languageList.forEach((lang) => { | ||
const option = document.createElement("option"); | ||
option.value = lang; | ||
option.innerText = !lang ? "--" : lang; | ||
if (lang === node.attrs["language"]) { | ||
option.selected = true; | ||
} | ||
select.appendChild(option); | ||
}); | ||
select.onchange = (e) => { | ||
const target = e.target; | ||
if (!(target instanceof HTMLSelectElement)) { | ||
return; | ||
} | ||
const view = ctx.get(editorViewCtx); | ||
if (!view.editable) { | ||
target.value = node.attrs["language"]; | ||
return; | ||
} | ||
const { top, left } = target.getBoundingClientRect(); | ||
const result = view.posAtCoords({ top, left }); | ||
if (!result) | ||
return; | ||
const { tr } = view.state; | ||
view.dispatch(tr.setNodeMarkup(result.inside, void 0, __spreadProps(__spreadValues({}, node.attrs), { | ||
language: target.value | ||
}))); | ||
}; | ||
return [ | ||
"pre", | ||
"div", | ||
{ | ||
"data-language": node.attrs["language"], | ||
class: utils.getClassName(node.attrs, "code-fence", style) | ||
class: "code-fence-container" | ||
}, | ||
["code", { spellCheck: "false" }, 0] | ||
select, | ||
[ | ||
"pre", | ||
{ | ||
"data-language": node.attrs["language"], | ||
class: utils.getClassName(node.attrs, "code-fence") | ||
}, | ||
["code", { spellCheck: "false" }, 0] | ||
] | ||
]; | ||
@@ -556,83 +518,45 @@ }, | ||
}, | ||
view: (ctx) => (node, view, getPos) => { | ||
const container = document.createElement("div"); | ||
const selectWrapper = document.createElement("div"); | ||
const select = document.createElement("ul"); | ||
const pre = document.createElement("pre"); | ||
const code = document.createElement("code"); | ||
const valueWrapper = document.createElement("div"); | ||
valueWrapper.className = "code-fence_value"; | ||
const value = document.createElement("span"); | ||
valueWrapper.appendChild(value); | ||
if (view.editable) { | ||
valueWrapper.appendChild(ctx.get(themeToolCtx).slots.icon("downArrow")); | ||
} | ||
select.className = "code-fence_select"; | ||
select.addEventListener("mousedown", (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (!view.editable) | ||
return; | ||
const el = e.target; | ||
if (!(el instanceof HTMLLIElement)) | ||
return; | ||
view: () => (node, view, getPos) => { | ||
let currNode = node; | ||
const onSelectLanguage = (language) => { | ||
const { tr } = view.state; | ||
view.dispatch(tr.setNodeMarkup(getPos(), void 0, { | ||
fold: true, | ||
language: el.dataset["value"] | ||
language | ||
})); | ||
}); | ||
valueWrapper.addEventListener("mousedown", (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (!view.editable) | ||
return; | ||
}; | ||
const onBlur = () => { | ||
const { tr } = view.state; | ||
view.dispatch(tr.setNodeMarkup(getPos(), void 0, { | ||
fold: false, | ||
language: container.dataset["language"] | ||
})); | ||
}); | ||
document.addEventListener("mousedown", () => { | ||
if (!view.editable || select.dataset["fold"] === "true") | ||
return; | ||
view.dispatch(tr.setNodeMarkup(getPos(), void 0, __spreadProps(__spreadValues({}, currNode.attrs), { | ||
fold: true | ||
}))); | ||
}; | ||
const onFocus = () => { | ||
const { tr } = view.state; | ||
view.dispatch(tr.setNodeMarkup(getPos(), void 0, { | ||
fold: true, | ||
language: container.dataset["language"] | ||
})); | ||
view.dispatch(tr.setNodeMarkup(getPos(), void 0, __spreadProps(__spreadValues({}, currNode.attrs), { | ||
fold: false | ||
}))); | ||
}; | ||
const renderer = utils.themeManager.get("code-fence", { | ||
onBlur, | ||
onFocus, | ||
onSelectLanguage, | ||
editable: () => view.editable, | ||
languageList | ||
}); | ||
((options == null ? void 0 : options.languageList) || languageOptions).forEach((lang) => { | ||
const option = document.createElement("li"); | ||
option.className = "code-fence_select-option"; | ||
option.innerText = lang || "--"; | ||
select.appendChild(option); | ||
option.setAttribute("data-value", lang); | ||
}); | ||
code.spellcheck = false; | ||
selectWrapper.className = "code-fence_select-wrapper"; | ||
selectWrapper.contentEditable = "false"; | ||
selectWrapper.append(valueWrapper); | ||
selectWrapper.append(select); | ||
pre.append(code); | ||
const codeContent = document.createElement("div"); | ||
code.append(codeContent); | ||
codeContent.style.whiteSpace = "inherit"; | ||
container.append(selectWrapper, pre); | ||
container.setAttribute("class", utils.getClassName(node.attrs, "code-fence", style)); | ||
container.setAttribute("data-language", node.attrs["language"]); | ||
value.innerText = node.attrs["language"] || "--"; | ||
select.setAttribute("data-fold", node.attrs["fold"] ? "true" : "false"); | ||
if (!renderer) | ||
return {}; | ||
const { dom, contentDOM, onUpdate, onDestroy } = renderer; | ||
onUpdate(currNode); | ||
return { | ||
dom: container, | ||
contentDOM: codeContent, | ||
dom, | ||
contentDOM, | ||
update: (updatedNode) => { | ||
if (updatedNode.type.name !== id$5) | ||
return false; | ||
const lang = updatedNode.attrs["language"]; | ||
container.dataset["language"] = lang; | ||
value.innerText = lang || "--"; | ||
select.setAttribute("data-fold", updatedNode.attrs["fold"] ? "true" : "false"); | ||
currNode = updatedNode; | ||
onUpdate(currNode); | ||
return true; | ||
} | ||
}, | ||
destroy: onDestroy | ||
}; | ||
@@ -735,35 +659,2 @@ } | ||
const id2 = "heading"; | ||
const style = (level) => utils.getStyle((_, { css }) => { | ||
const headingMap = { | ||
1: css` | ||
font-size: 3rem; | ||
line-height: 3.5rem; | ||
`, | ||
2: css` | ||
font-size: 2.5rem; | ||
line-height: 3rem; | ||
`, | ||
3: css` | ||
font-size: 2.125rem; | ||
line-height: 2.25rem; | ||
`, | ||
4: css` | ||
font-size: 1.75rem; | ||
line-height: 2rem; | ||
`, | ||
5: css` | ||
font-size: 1.5rem; | ||
line-height: 1.5rem; | ||
`, | ||
6: css` | ||
font-size: 1.25rem; | ||
line-height: 1.25rem; | ||
` | ||
}; | ||
return css` | ||
${headingMap[level] || ""} | ||
margin: 2.5rem 0 !important; | ||
font-weight: 400; | ||
`; | ||
}); | ||
return { | ||
@@ -797,3 +688,3 @@ id: id2, | ||
id: node.attrs["id"] || node.textContent.split(" ").join("-").toLocaleLowerCase(), | ||
class: utils.getClassName(node.attrs, `heading h${node.attrs["level"]}`, style(node.attrs["level"])) | ||
class: utils.getClassName(node.attrs, `heading h${node.attrs["level"]}`) | ||
}, | ||
@@ -892,7 +783,2 @@ 0 | ||
const hr = createNode((utils) => { | ||
const style = utils.getStyle((themeTool, { css }) => css` | ||
height: ${themeTool.size.lineWidth}; | ||
background-color: ${themeTool.palette("line")}; | ||
border-width: 0; | ||
`); | ||
return { | ||
@@ -903,3 +789,3 @@ id: id$4, | ||
parseDOM: [{ tag: "hr" }], | ||
toDOM: (node) => ["hr", { class: utils.getClassName(node.attrs, id$4, style) }], | ||
toDOM: (node) => ["hr", { class: utils.getClassName(node.attrs, id$4) }], | ||
parseMarkdown: { | ||
@@ -951,111 +837,4 @@ match: ({ type }) => type === "thematicBreak", | ||
const id$3 = "image"; | ||
const key = new PluginKey("MILKDOWN_PLUGIN_IMAGE_INPUT"); | ||
const image = createNode((utils, options) => { | ||
var _a, _b; | ||
const placeholder = __spreadValues({ | ||
loading: "Loading...", | ||
empty: "Add an Image", | ||
failed: "Image loads failed" | ||
}, (_a = options == null ? void 0 : options.placeholder) != null ? _a : {}); | ||
const isBlock = (_b = options == null ? void 0 : options.isBlock) != null ? _b : false; | ||
const containerStyle = utils.getStyle((themeTool, { css }) => css` | ||
display: inline-block; | ||
position: relative; | ||
text-align: center; | ||
font-size: 0; | ||
vertical-align: text-bottom; | ||
line-height: 1; | ||
${isBlock ? ` | ||
width: 100%; | ||
margin: 0 auto; | ||
` : ""} | ||
&.ProseMirror-selectednode::after { | ||
content: ''; | ||
background: ${themeTool.palette("secondary", 0.38)}; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
right: 0; | ||
bottom: 0; | ||
} | ||
img { | ||
max-width: 100%; | ||
height: auto; | ||
object-fit: contain; | ||
margin: 0 2px; | ||
} | ||
.icon, | ||
.placeholder { | ||
display: none; | ||
} | ||
&.system { | ||
width: 100%; | ||
padding: 0 2rem; | ||
img { | ||
width: 0; | ||
height: 0; | ||
display: none; | ||
} | ||
.icon, | ||
.placeholder { | ||
display: inline; | ||
} | ||
box-sizing: border-box; | ||
height: 3rem; | ||
background-color: ${themeTool.palette("background")}; | ||
border-radius: ${themeTool.size.radius}; | ||
display: inline-flex; | ||
gap: 2rem; | ||
justify-content: flex-start; | ||
align-items: center; | ||
.placeholder { | ||
margin: 0; | ||
line-height: 1; | ||
&::before { | ||
content: ''; | ||
font-size: 0.875rem; | ||
color: ${themeTool.palette("neutral", 0.6)}; | ||
} | ||
} | ||
} | ||
&.loading { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.loading}'; | ||
} | ||
} | ||
} | ||
&.empty { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.empty}'; | ||
} | ||
} | ||
} | ||
&.failed { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.failed}'; | ||
} | ||
} | ||
} | ||
`); | ||
const style = utils.getStyle((_, { css }) => css` | ||
display: inline-block; | ||
margin: 0 auto; | ||
object-fit: contain; | ||
width: 100%; | ||
position: relative; | ||
height: auto; | ||
text-align: center; | ||
`); | ||
return { | ||
@@ -1075,6 +854,3 @@ id: "image", | ||
alt: { default: null }, | ||
title: { default: null }, | ||
failed: { default: false }, | ||
loading: { default: true }, | ||
width: { default: null } | ||
title: { default: null } | ||
}, | ||
@@ -1089,4 +865,2 @@ parseDOM: [ | ||
return { | ||
failed: dom.classList.contains("failed"), | ||
loading: dom.classList.contains("loading"), | ||
src: dom.getAttribute("src") || "", | ||
@@ -1104,3 +878,3 @@ alt: dom.getAttribute("alt"), | ||
__spreadProps(__spreadValues({}, node.attrs), { | ||
class: utils.getClassName(node.attrs, id$3, node.attrs["failed"] ? "failed" : "", node.attrs["loading"] ? "loading" : "", style) | ||
class: utils.getClassName(node.attrs, id$3) | ||
}) | ||
@@ -1165,99 +939,84 @@ ]; | ||
], | ||
view: (ctx) => (node, view, getPos) => { | ||
const nodeType = node.type; | ||
const createIcon = ctx.get(themeToolCtx).slots.icon; | ||
const container = document.createElement("span"); | ||
container.className = utils.getClassName(node.attrs, id$3, containerStyle); | ||
const content = document.createElement("img"); | ||
container.append(content); | ||
let icon = createIcon("image"); | ||
const placeholder2 = document.createElement("span"); | ||
placeholder2.classList.add("placeholder"); | ||
container.append(icon, placeholder2); | ||
const setIcon = (name) => { | ||
const nextIcon = createIcon(name); | ||
container.replaceChild(nextIcon, icon); | ||
icon = nextIcon; | ||
}; | ||
const loadImage = (src2) => { | ||
container.classList.add("system", "loading"); | ||
setIcon("loading"); | ||
const img = document.createElement("img"); | ||
img.src = src2; | ||
img.onerror = () => { | ||
const pos = getPos(); | ||
if (!pos) | ||
return; | ||
const { tr } = view.state; | ||
const _tr = tr.setNodeMarkup(pos, nodeType, __spreadProps(__spreadValues({}, node.attrs), { | ||
src: src2, | ||
loading: false, | ||
failed: true | ||
})); | ||
view.dispatch(_tr); | ||
}; | ||
img.onload = () => { | ||
const { tr } = view.state; | ||
const pos = getPos(); | ||
if (!pos) | ||
return; | ||
const _tr = tr.setNodeMarkup(pos, nodeType, __spreadProps(__spreadValues({}, node.attrs), { | ||
width: img.width, | ||
src: src2, | ||
loading: false, | ||
failed: false | ||
})); | ||
view.dispatch(_tr); | ||
}; | ||
}; | ||
const { src, loading, title, alt, width } = node.attrs; | ||
content.src = src; | ||
content.title = title || alt; | ||
content.alt = alt; | ||
if (width) { | ||
content.width = width; | ||
view: () => (node) => { | ||
var _a, _b; | ||
let currNode = node; | ||
const placeholder = (_a = options == null ? void 0 : options.placeholder) != null ? _a : "Add an Image"; | ||
const isBlock = (_b = options == null ? void 0 : options.isBlock) != null ? _b : false; | ||
const renderer = utils.themeManager.get("image", { | ||
placeholder, | ||
isBlock | ||
}); | ||
if (!renderer) { | ||
return {}; | ||
} | ||
if (src.length === 0) { | ||
container.classList.add("system", "empty"); | ||
setIcon("image"); | ||
} else if (loading) { | ||
loadImage(src); | ||
} | ||
const { dom, onUpdate } = renderer; | ||
onUpdate(currNode); | ||
return { | ||
dom: container, | ||
dom, | ||
update: (updatedNode) => { | ||
if (updatedNode.type.name !== id$3) | ||
return false; | ||
const { src: src2, alt: alt2, title: title2, loading: loading2, failed, width: width2 } = updatedNode.attrs; | ||
content.src = src2; | ||
content.alt = alt2; | ||
content.title = title2 || alt2; | ||
if (width2) { | ||
content.width = width2; | ||
} | ||
if (loading2) { | ||
loadImage(src2); | ||
return true; | ||
} | ||
if (failed) { | ||
container.classList.remove("loading", "empty"); | ||
container.classList.add("system", "failed"); | ||
setIcon("brokenImage"); | ||
return true; | ||
} | ||
if (src2.length > 0) { | ||
container.classList.remove("system", "empty", "loading"); | ||
return true; | ||
} | ||
container.classList.add("system", "empty"); | ||
setIcon("image"); | ||
currNode = updatedNode; | ||
onUpdate(currNode); | ||
return true; | ||
}, | ||
selectNode: () => { | ||
container.classList.add("ProseMirror-selectednode"); | ||
dom.classList.add("ProseMirror-selectednode"); | ||
}, | ||
deselectNode: () => { | ||
container.classList.remove("ProseMirror-selectednode"); | ||
dom.classList.remove("ProseMirror-selectednode"); | ||
} | ||
}; | ||
}, | ||
prosePlugins: (type, ctx) => { | ||
var _a, _b, _c; | ||
const inputChipRenderer = utils.themeManager.get("input-chip", { | ||
placeholder: (_b = (_a = options == null ? void 0 : options.input) == null ? void 0 : _a.placeholder) != null ? _b : "Input Image Link", | ||
buttonText: (_c = options == null ? void 0 : options.input) == null ? void 0 : _c.buttonText, | ||
onUpdate: (value) => { | ||
ctx.get(commandsCtx).call(ModifyImage, value); | ||
} | ||
}); | ||
const shouldDisplay = (view) => { | ||
return Boolean(type && findSelectedNodeOfType(view.state.selection, type)); | ||
}; | ||
const getCurrentLink = (view) => { | ||
const result = findSelectedNodeOfType(view.state.selection, type); | ||
if (!result) | ||
return; | ||
const value = result.node.attrs["src"]; | ||
return value; | ||
}; | ||
const renderByView = (view) => { | ||
if (!view.editable) { | ||
return; | ||
} | ||
const display = shouldDisplay(view); | ||
if (display) { | ||
inputChipRenderer.show(view); | ||
inputChipRenderer.update(getCurrentLink(view)); | ||
} else { | ||
inputChipRenderer.hide(); | ||
} | ||
}; | ||
return [ | ||
new Plugin({ | ||
key, | ||
view: (editorView) => { | ||
inputChipRenderer.init(editorView); | ||
renderByView(editorView); | ||
return { | ||
update: (view, prevState) => { | ||
const isEqualSelection = (prevState == null ? void 0 : prevState.doc.eq(view.state.doc)) && prevState.selection.eq(view.state.selection); | ||
if (isEqualSelection) | ||
return; | ||
renderByView(view); | ||
}, | ||
destroy: () => { | ||
inputChipRenderer.destroy(); | ||
} | ||
}; | ||
} | ||
}) | ||
]; | ||
} | ||
@@ -1270,54 +1029,39 @@ }; | ||
const LiftListItem = createCmdKey("LiftListItem"); | ||
const listItem = createNode((utils) => { | ||
const style = utils.getStyle((themeTool, { css }) => css` | ||
&, | ||
& > * { | ||
margin: 0.5rem 0; | ||
} | ||
&, | ||
li { | ||
&::marker { | ||
color: ${themeTool.palette("primary")}; | ||
} | ||
} | ||
`); | ||
return { | ||
id: id$2, | ||
schema: () => ({ | ||
group: "listItem", | ||
content: "paragraph block*", | ||
defining: true, | ||
parseDOM: [{ tag: "li" }], | ||
toDOM: (node) => ["li", { class: utils.getClassName(node.attrs, "list-item", style) }, 0], | ||
parseMarkdown: { | ||
match: ({ type, checked }) => type === "listItem" && checked === null, | ||
runner: (state, node, type) => { | ||
state.openNode(type); | ||
state.next(node.children); | ||
state.closeNode(); | ||
} | ||
}, | ||
toMarkdown: { | ||
match: (node) => node.type.name === id$2, | ||
runner: (state, node) => { | ||
state.openNode("listItem"); | ||
state.next(node.content); | ||
state.closeNode(); | ||
} | ||
const listItem = createNode((utils) => ({ | ||
id: id$2, | ||
schema: () => ({ | ||
group: "listItem", | ||
content: "paragraph block*", | ||
defining: true, | ||
parseDOM: [{ tag: "li" }], | ||
toDOM: (node) => ["li", { class: utils.getClassName(node.attrs, "list-item") }, 0], | ||
parseMarkdown: { | ||
match: ({ type, checked }) => type === "listItem" && checked === null, | ||
runner: (state, node, type) => { | ||
state.openNode(type); | ||
state.next(node.children); | ||
state.closeNode(); | ||
} | ||
}), | ||
inputRules: (nodeType) => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)], | ||
commands: (nodeType) => [ | ||
createCmd(SplitListItem, () => splitListItem(nodeType)), | ||
createCmd(SinkListItem, () => sinkListItem(nodeType)), | ||
createCmd(LiftListItem, () => liftListItem(nodeType)) | ||
], | ||
shortcuts: { | ||
[SupportedKeys.NextListItem]: createShortcut(SplitListItem, "Enter"), | ||
[SupportedKeys.SinkListItem]: createShortcut(SinkListItem, "Mod-]"), | ||
[SupportedKeys.LiftListItem]: createShortcut(LiftListItem, "Mod-[") | ||
}, | ||
toMarkdown: { | ||
match: (node) => node.type.name === id$2, | ||
runner: (state, node) => { | ||
state.openNode("listItem"); | ||
state.next(node.content); | ||
state.closeNode(); | ||
} | ||
} | ||
}; | ||
}); | ||
}), | ||
inputRules: (nodeType) => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)], | ||
commands: (nodeType) => [ | ||
createCmd(SplitListItem, () => splitListItem(nodeType)), | ||
createCmd(SinkListItem, () => sinkListItem(nodeType)), | ||
createCmd(LiftListItem, () => liftListItem(nodeType)) | ||
], | ||
shortcuts: { | ||
[SupportedKeys.NextListItem]: createShortcut(SplitListItem, "Enter"), | ||
[SupportedKeys.SinkListItem]: createShortcut(SinkListItem, "Mod-]"), | ||
[SupportedKeys.LiftListItem]: createShortcut(LiftListItem, "Mod-[") | ||
} | ||
})); | ||
const WrapInOrderedList = createCmdKey("WrapInOrderedList"); | ||
@@ -1379,9 +1123,2 @@ const id$1 = "ordered_list"; | ||
const paragraph = createNode((utils) => { | ||
const style = utils.getStyle((_, { css }) => { | ||
return css` | ||
font-size: 1rem; | ||
line-height: 1.5; | ||
letter-spacing: 0.5px; | ||
`; | ||
}); | ||
return { | ||
@@ -1393,3 +1130,3 @@ id, | ||
parseDOM: [{ tag: "p" }], | ||
toDOM: (node) => ["p", { class: utils.getClassName(node.attrs, id, style) }, 0], | ||
toDOM: (node) => ["p", { class: utils.getClassName(node.attrs, id) }, 0], | ||
parseMarkdown: { | ||
@@ -1396,0 +1133,0 @@ match: (node) => node.type === "paragraph", |
{ | ||
"name": "@milkdown/preset-commonmark", | ||
"version": "5.5.0", | ||
"version": "6.0.0-next.0", | ||
"type": "module", | ||
@@ -20,22 +20,45 @@ "main": "./lib/index.es.js", | ||
"devDependencies": { | ||
"@milkdown/core": "5.5.0", | ||
"@milkdown/prose": "5.5.0", | ||
"@milkdown/design-system": "5.5.0" | ||
"@milkdown/core": "6.0.0-next.0", | ||
"@milkdown/prose": "6.0.0-next.0" | ||
}, | ||
"peerDependencies": { | ||
"@milkdown/core": "^5.4.0", | ||
"@milkdown/prose": "^5.4.0" | ||
"@milkdown/core": "^6.0.0-next.0", | ||
"@milkdown/prose": "^6.0.0-next.0" | ||
}, | ||
"dependencies": { | ||
"@milkdown/utils": "5.5.0", | ||
"@milkdown/utils": "6.0.0-next.0", | ||
"remark-inline-links": "^6.0.0", | ||
"tslib": "^2.3.1" | ||
}, | ||
"nx": { | ||
"targets": { | ||
"build": { | ||
"outputs": [ | ||
"packages/preset-commonmark/lib" | ||
], | ||
"dependsOn": [ | ||
{ | ||
"target": "build", | ||
"projects": "dependencies" | ||
} | ||
] | ||
}, | ||
"tsc": { | ||
"outputs": [], | ||
"dependsOn": [ | ||
{ | ||
"target": "build", | ||
"projects": "dependencies" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"scripts": { | ||
"start": "vite build --watch", | ||
"start": "concurrently -n es,dts \"vite build --watch\" \"tsc --emitDeclarationOnly --watch\"", | ||
"test": "vitest", | ||
"tsc": "tsc --noEmit", | ||
"build": "vite build" | ||
"build": "vite build && tsc --emitDeclarationOnly" | ||
}, | ||
"readme": "# @milkdown/preset-commonmark\n\nCommon mark preset for [milkdown](https://saul-mirone.github.io/milkdown/).\nAdd support for commonmark.\n\n# Example Usage\n\n```typescript\nimport { Editor } from '@milkdown/core';\nimport { nord } from '@milkdown/theme-nord';\n\nimport { commonmark } from '@milkdown/preset-commonmark';\n\nEditor.make().use(nord).use(commonmark).create();\n```\n\n## Custom Keymap\n\n```typescript\nimport { commonmarkNodes, commonmarkPlugins, blockquote, SupportedKeys } from '@milkdown/preset-commonmark';\n\nconst nodes = commonmarkNodes.configure(blockquote, {\n keymap: {\n [SupportedKeys.Blockquote]: 'Mod-Shift-b',\n },\n});\n\nEditor.make().use(commonmarkPlugins).use(nodes);\n```\n\nKeymap supported:\n\n- HardBreak\n- Blockquote\n- BulletList\n- OrderedList\n- CodeFence\n- H1\n- H2\n- H3\n- H4\n- H5\n- H6\n- Text\n- CodeInline\n- Em\n- Bold\n- NextListItem\n- SinkListItem\n- LiftListItem\n\n## Custom Style\n\n```typescript\nimport { commonmark, Paragraph, Heading } from '@milkdown/commonmark';\n\nconst nodes = commonmark\n .configure(Paragraph, {\n className: () =>\n 'my-custom-paragraph'\n })\n .configure(Heading, {\n className: (attrs) =>\n `my-custom-heading my-h${attrs.level}`\n })\n\nnew Editor({ ... }).use(nodes);\n```\n\n## Other Options\n\n### Image\n\n- placeholder\n - loading: _string_. The placeholder of loading status.\n - empty: _string_. The placeholder of empty status.\n - failed: _string_. The placeholder of failed status.\n\n### CodeFence\n\n- languageList: _string[]_. The selectable languages list of code fence needs to be enabled.\n\n# License\n\nMilkdown is open sourced software licensed under [MIT license](https://github.com/Saul-Mirone/milkdown/blob/main/LICENSE).\n" | ||
"readme": "# @milkdown/preset-commonmark\n\nCommon mark preset for [milkdown](https://saul-mirone.github.io/milkdown/).\nAdd support for commonmark.\n\n# Example Usage\n\n```typescript\nimport { Editor } from '@milkdown/core';\nimport { nord } from '@milkdown/theme-nord';\n\nimport { commonmark } from '@milkdown/preset-commonmark';\n\nEditor.make().use(nord).use(commonmark).create();\n```\n\n## Custom Keymap\n\n```typescript\nimport { commonmarkNodes, commonmarkPlugins, blockquote, SupportedKeys } from '@milkdown/preset-commonmark';\n\nconst nodes = commonmarkNodes.configure(blockquote, {\n keymap: {\n [SupportedKeys.Blockquote]: 'Mod-Shift-b',\n },\n});\n\nEditor.make().use(commonmarkPlugins).use(nodes);\n```\n\nKeymap supported:\n\n- HardBreak\n- Blockquote\n- BulletList\n- OrderedList\n- CodeFence\n- H1\n- H2\n- H3\n- H4\n- H5\n- H6\n- Text\n- CodeInline\n- Em\n- Bold\n- NextListItem\n- SinkListItem\n- LiftListItem\n\n## Custom Style\n\n```typescript\nimport { commonmark, Paragraph, Heading } from '@milkdown/commonmark';\n\nconst nodes = commonmark\n .configure(Paragraph, {\n className: () =>\n 'my-custom-paragraph'\n })\n .configure(Heading, {\n className: (attrs) =>\n `my-custom-heading my-h${attrs.level}`\n })\n\nnew Editor({ ... }).use(nodes);\n```\n\n## Other Options\n\n### Image\n\n- placeholder: The placeholder of empty status.\n- isBlock: Whether the image is a block (render as a row).\n- input:\n - placeholder: The placeholder of image url input.\n - buttonText: The button text of image url input.\n\n### CodeFence\n\n- languageList: _string[]_. The selectable languages list of code fence needs to be enabled.\n\n# License\n\nMilkdown is open sourced software licensed under [MIT license](https://github.com/Saul-Mirone/milkdown/blob/main/LICENSE).\n" | ||
} |
@@ -74,6 +74,7 @@ # @milkdown/preset-commonmark | ||
- placeholder | ||
- loading: _string_. The placeholder of loading status. | ||
- empty: _string_. The placeholder of empty status. | ||
- failed: _string_. The placeholder of failed status. | ||
- placeholder: The placeholder of empty status. | ||
- isBlock: Whether the image is a block (render as a row). | ||
- input: | ||
- placeholder: The placeholder of image url input. | ||
- buttonText: The button text of image url input. | ||
@@ -80,0 +81,0 @@ ### CodeFence |
@@ -14,13 +14,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const codeInline = createMark<Keys>((utils) => { | ||
const style = utils.getStyle( | ||
({ palette, size, font }, { css }) => | ||
css` | ||
background-color: ${palette('neutral')}; | ||
color: ${palette('background')}; | ||
border-radius: ${size.radius}; | ||
font-weight: 500; | ||
font-family: ${font.code}; | ||
padding: 0 0.2rem; | ||
`, | ||
); | ||
return { | ||
@@ -33,3 +22,3 @@ id, | ||
parseDOM: [{ tag: 'code' }], | ||
toDOM: (mark) => ['code', { class: utils.getClassName(mark.attrs, 'code-inline', style) }], | ||
toDOM: (mark) => ['code', { class: utils.getClassName(mark.attrs, 'code-inline') }], | ||
parseMarkdown: { | ||
@@ -36,0 +25,0 @@ match: (node) => node.type === 'inlineCode', |
/* Copyright 2021, Milkdown by Mirone. */ | ||
import { createCmd, createCmdKey, schemaCtx } from '@milkdown/core'; | ||
import { InputRule, Node as ProseNode, TextSelection, toggleMark } from '@milkdown/prose'; | ||
import { commandsCtx, createCmd, createCmdKey, schemaCtx, ThemeInputChipType } from '@milkdown/core'; | ||
import { | ||
EditorView, | ||
InputRule, | ||
Node as ProseNode, | ||
Plugin, | ||
PluginKey, | ||
TextSelection, | ||
toggleMark, | ||
} from '@milkdown/prose'; | ||
import { createMark } from '@milkdown/utils'; | ||
const key = new PluginKey('MILKDOWN_PLUGIN_LINK_INPUT'); | ||
export const ToggleLink = createCmdKey<string>('ToggleLink'); | ||
export const ModifyLink = createCmdKey<string>('ModifyLink'); | ||
const id = 'link'; | ||
export const link = createMark((utils) => { | ||
const style = utils.getStyle((themeTool, { css }) => { | ||
const lineColor = themeTool.palette('line'); | ||
return css` | ||
color: ${themeTool.palette('secondary')}; | ||
cursor: pointer; | ||
transition: all 0.4s ease-in-out; | ||
font-weight: 500; | ||
&:hover { | ||
background-color: ${lineColor}; | ||
box-shadow: 0 0.2rem ${lineColor}, 0 -0.2rem ${lineColor}; | ||
} | ||
`; | ||
}); | ||
export type LinkOptions = { | ||
input: { | ||
placeholder: string; | ||
buttonText?: string; | ||
}; | ||
}; | ||
export const link = createMark<string, LinkOptions>((utils, options) => { | ||
return { | ||
@@ -43,3 +45,3 @@ id, | ||
], | ||
toDOM: (mark) => ['a', { ...mark.attrs, class: utils.getClassName(mark.attrs, id, style) }], | ||
toDOM: (mark) => ['a', { ...mark.attrs, class: utils.getClassName(mark.attrs, id) }], | ||
parseMarkdown: { | ||
@@ -119,3 +121,75 @@ match: (node) => node.type === 'link', | ||
], | ||
prosePlugins: (type, ctx) => { | ||
const inputChipRenderer = utils.themeManager.get<ThemeInputChipType>('input-chip', { | ||
placeholder: options?.input?.placeholder ?? 'Input Web Link', | ||
buttonText: options?.input?.buttonText, | ||
onUpdate: (value) => { | ||
ctx.get(commandsCtx).call(ModifyLink, value); | ||
}, | ||
}); | ||
const shouldDisplay = (view: EditorView) => { | ||
const { selection, doc } = view.state; | ||
const { from, to } = selection; | ||
return ( | ||
selection.empty && | ||
selection instanceof TextSelection && | ||
doc.rangeHasMark(from, from === to ? to + 1 : to, type) | ||
); | ||
}; | ||
const getCurrentLink = (view: EditorView) => { | ||
const { selection } = view.state; | ||
let node: ProseNode | undefined; | ||
const { from, to } = selection; | ||
view.state.doc.nodesBetween(from, from === to ? to + 1 : to, (n) => { | ||
if (type.isInSet(n.marks)) { | ||
node = n; | ||
return false; | ||
} | ||
return; | ||
}); | ||
if (!node) return; | ||
const mark = node.marks.find((m) => m.type === type); | ||
if (!mark) return; | ||
const value = mark.attrs['href']; | ||
return value; | ||
}; | ||
const renderByView = (view: EditorView) => { | ||
if (!view.editable) { | ||
return; | ||
} | ||
const display = shouldDisplay(view); | ||
if (display) { | ||
inputChipRenderer.show(view); | ||
inputChipRenderer.update(getCurrentLink(view)); | ||
} else { | ||
inputChipRenderer.hide(); | ||
} | ||
}; | ||
return [ | ||
new Plugin({ | ||
key, | ||
view: (editorView) => { | ||
inputChipRenderer.init(editorView); | ||
renderByView(editorView); | ||
return { | ||
update: (view, prevState) => { | ||
const isEqualSelection = | ||
prevState?.doc.eq(view.state.doc) && prevState.selection.eq(view.state.selection); | ||
if (isEqualSelection) return; | ||
renderByView(view); | ||
}, | ||
destroy: () => { | ||
inputChipRenderer.destroy(); | ||
}, | ||
}; | ||
}, | ||
}), | ||
]; | ||
}, | ||
}; | ||
}); |
@@ -12,8 +12,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const strong = createMark<Keys>((utils) => { | ||
const style = utils.getStyle( | ||
(_, { css }) => | ||
css` | ||
font-weight: 600; | ||
`, | ||
); | ||
return { | ||
@@ -27,3 +21,3 @@ id, | ||
], | ||
toDOM: (mark) => ['strong', { class: utils.getClassName(mark.attrs, id, style) }], | ||
toDOM: (mark) => ['strong', { class: utils.getClassName(mark.attrs, id) }], | ||
parseMarkdown: { | ||
@@ -30,0 +24,0 @@ match: (node) => node.type === 'strong', |
@@ -15,15 +15,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const blockquote = createNode<Keys>((utils) => { | ||
const style = utils.getStyle( | ||
(themeTool, { css }) => | ||
css` | ||
padding-left: 1.875rem; | ||
line-height: 1.75rem; | ||
border-left: 4px solid ${themeTool.palette('primary')}; | ||
* { | ||
font-size: 1rem; | ||
line-height: 1.5rem; | ||
} | ||
`, | ||
); | ||
return { | ||
@@ -36,3 +23,3 @@ id, | ||
parseDOM: [{ tag: 'blockquote' }], | ||
toDOM: (node) => ['blockquote', { class: utils.getClassName(node.attrs, id, style) }, 0], | ||
toDOM: (node) => ['blockquote', { class: utils.getClassName(node.attrs, id) }, 0], | ||
parseMarkdown: { | ||
@@ -39,0 +26,0 @@ match: ({ type }) => type === id, |
/* Copyright 2021, Milkdown by Mirone. */ | ||
import { createCmd, createCmdKey, themeToolCtx } from '@milkdown/core'; | ||
import { createCmd, createCmdKey, editorViewCtx, ThemeCodeFenceType } from '@milkdown/core'; | ||
import { setBlockType, textblockTypeInputRule } from '@milkdown/prose'; | ||
@@ -36,115 +36,7 @@ import { createNode, createShortcut } from '@milkdown/utils'; | ||
export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, options) => { | ||
const style = utils.getStyle(({ palette, mixin, size, font }, { css }) => { | ||
const { shadow, scrollbar, border } = mixin; | ||
const { lineWidth, radius } = size; | ||
return css` | ||
background-color: ${palette('background')}; | ||
color: ${palette('neutral')}; | ||
font-size: 0.85rem; | ||
padding: 1.2rem 0.4rem 1.4rem; | ||
border-radius: ${radius}; | ||
font-family: ${font.typography}; | ||
const languageList = options?.languageList || languageOptions; | ||
* { | ||
margin: 0; | ||
} | ||
.code-fence_select-wrapper { | ||
position: relative; | ||
} | ||
.code-fence_value { | ||
width: 10.25rem; | ||
box-sizing: border-box; | ||
border-radius: ${size.radius}; | ||
margin: 0 1.2rem 1.2rem; | ||
${border()}; | ||
${shadow()}; | ||
cursor: pointer; | ||
background-color: ${palette('surface')}; | ||
position: relative; | ||
display: flex; | ||
color: ${palette('neutral', 0.87)}; | ||
letter-spacing: 0.5px; | ||
height: 2.625rem; | ||
align-items: center; | ||
& > .icon { | ||
width: 2.625rem; | ||
height: 100%; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
color: ${palette('solid', 0.87)}; | ||
border-left: ${lineWidth} solid ${palette('line')}; | ||
text-align: center; | ||
transition: all 0.2s ease-in-out; | ||
&:hover { | ||
background: ${palette('background')}; | ||
color: ${palette('primary')}; | ||
} | ||
} | ||
> span:first-child { | ||
padding-left: 1rem; | ||
flex: 1; | ||
font-weight: 500; | ||
} | ||
} | ||
.code-fence_select-option { | ||
list-style: none; | ||
line-height: 2rem; | ||
padding-left: 1rem; | ||
cursor: pointer; | ||
:hover { | ||
background: ${palette('secondary', 0.12)}; | ||
color: ${palette('primary')}; | ||
} | ||
} | ||
.code-fence_select { | ||
&[data-fold='true'] { | ||
display: none; | ||
} | ||
font-weight: 500; | ||
position: absolute; | ||
z-index: 1; | ||
top: 2.625rem; | ||
box-sizing: border-box; | ||
left: 1.2rem; | ||
padding: 0.5rem 0; | ||
max-height: 16.75rem; | ||
width: 10.25rem; | ||
${border()}; | ||
${shadow()}; | ||
background-color: ${palette('surface')}; | ||
border-top: none; | ||
overflow-y: auto; | ||
display: flex; | ||
flex-direction: column; | ||
${scrollbar('y')} | ||
} | ||
code { | ||
line-height: 1.5; | ||
font-family: ${font.code}; | ||
} | ||
pre { | ||
font-family: ${font.code}; | ||
margin: 0 1.2rem !important; | ||
white-space: pre; | ||
overflow: auto; | ||
${scrollbar('x')}; | ||
} | ||
`; | ||
}); | ||
return { | ||
id, | ||
schema: () => ({ | ||
schema: (ctx) => ({ | ||
content: 'text*', | ||
@@ -176,9 +68,50 @@ group: 'block', | ||
toDOM: (node) => { | ||
const select = document.createElement('select'); | ||
languageList.forEach((lang) => { | ||
const option = document.createElement('option'); | ||
option.value = lang; | ||
option.innerText = !lang ? '--' : lang; | ||
if (lang === node.attrs['language']) { | ||
option.selected = true; | ||
} | ||
select.appendChild(option); | ||
}); | ||
select.onchange = (e) => { | ||
const target = e.target; | ||
if (!(target instanceof HTMLSelectElement)) { | ||
return; | ||
} | ||
const view = ctx.get(editorViewCtx); | ||
if (!view.editable) { | ||
target.value = node.attrs['language']; | ||
return; | ||
} | ||
const { top, left } = target.getBoundingClientRect(); | ||
const result = view.posAtCoords({ top, left }); | ||
if (!result) return; | ||
const { tr } = view.state; | ||
view.dispatch( | ||
tr.setNodeMarkup(result.inside, undefined, { | ||
...node.attrs, | ||
language: target.value, | ||
}), | ||
); | ||
}; | ||
return [ | ||
'pre', | ||
'div', | ||
{ | ||
'data-language': node.attrs['language'], | ||
class: utils.getClassName(node.attrs, 'code-fence', style), | ||
class: 'code-fence-container', | ||
}, | ||
['code', { spellCheck: 'false' }, 0], | ||
select, | ||
[ | ||
'pre', | ||
{ | ||
'data-language': node.attrs['language'], | ||
class: utils.getClassName(node.attrs, 'code-fence'), | ||
}, | ||
['code', { spellCheck: 'false' }, 0], | ||
], | ||
]; | ||
@@ -223,40 +156,15 @@ }, | ||
}, | ||
view: (ctx) => (node, view, getPos) => { | ||
const container = document.createElement('div'); | ||
const selectWrapper = document.createElement('div'); | ||
const select = document.createElement('ul'); | ||
const pre = document.createElement('pre'); | ||
const code = document.createElement('code'); | ||
view: () => (node, view, getPos) => { | ||
let currNode = node; | ||
const valueWrapper = document.createElement('div'); | ||
valueWrapper.className = 'code-fence_value'; | ||
const value = document.createElement('span'); | ||
valueWrapper.appendChild(value); | ||
if (view.editable) { | ||
valueWrapper.appendChild(ctx.get(themeToolCtx).slots.icon('downArrow')); | ||
} | ||
select.className = 'code-fence_select'; | ||
select.addEventListener('mousedown', (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (!view.editable) return; | ||
const el = e.target; | ||
if (!(el instanceof HTMLLIElement)) return; | ||
const onSelectLanguage = (language: string) => { | ||
const { tr } = view.state; | ||
view.dispatch( | ||
tr.setNodeMarkup(getPos(), undefined, { | ||
fold: true, | ||
language: el.dataset['value'], | ||
language, | ||
}), | ||
); | ||
}); | ||
valueWrapper.addEventListener('mousedown', (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (!view.editable) return; | ||
}; | ||
const onBlur = () => { | ||
const { tr } = view.state; | ||
@@ -266,10 +174,8 @@ | ||
tr.setNodeMarkup(getPos(), undefined, { | ||
fold: false, | ||
language: container.dataset['language'], | ||
...currNode.attrs, | ||
fold: true, | ||
}), | ||
); | ||
}); | ||
document.addEventListener('mousedown', () => { | ||
if (!view.editable || select.dataset['fold'] === 'true') return; | ||
}; | ||
const onFocus = () => { | ||
const { tr } = view.state; | ||
@@ -279,45 +185,31 @@ | ||
tr.setNodeMarkup(getPos(), undefined, { | ||
fold: true, | ||
language: container.dataset['language'], | ||
...currNode.attrs, | ||
fold: false, | ||
}), | ||
); | ||
}); | ||
}; | ||
(options?.languageList || languageOptions).forEach((lang) => { | ||
const option = document.createElement('li'); | ||
option.className = 'code-fence_select-option'; | ||
option.innerText = lang || '--'; | ||
select.appendChild(option); | ||
option.setAttribute('data-value', lang); | ||
const renderer = utils.themeManager.get<ThemeCodeFenceType>('code-fence', { | ||
onBlur, | ||
onFocus, | ||
onSelectLanguage, | ||
editable: () => view.editable, | ||
languageList, | ||
}); | ||
if (!renderer) return {}; | ||
code.spellcheck = false; | ||
selectWrapper.className = 'code-fence_select-wrapper'; | ||
selectWrapper.contentEditable = 'false'; | ||
selectWrapper.append(valueWrapper); | ||
selectWrapper.append(select); | ||
pre.append(code); | ||
const codeContent = document.createElement('div'); | ||
code.append(codeContent); | ||
codeContent.style.whiteSpace = 'inherit'; | ||
const { dom, contentDOM, onUpdate, onDestroy } = renderer; | ||
onUpdate(currNode); | ||
container.append(selectWrapper, pre); | ||
container.setAttribute('class', utils.getClassName(node.attrs, 'code-fence', style)); | ||
container.setAttribute('data-language', node.attrs['language']); | ||
value.innerText = node.attrs['language'] || '--'; | ||
select.setAttribute('data-fold', node.attrs['fold'] ? 'true' : 'false'); | ||
return { | ||
dom: container, | ||
contentDOM: codeContent, | ||
dom, | ||
contentDOM, | ||
update: (updatedNode) => { | ||
if (updatedNode.type.name !== id) return false; | ||
currNode = updatedNode; | ||
onUpdate(currNode); | ||
const lang = updatedNode.attrs['language']; | ||
container.dataset['language'] = lang; | ||
value.innerText = lang || '--'; | ||
select.setAttribute('data-fold', updatedNode.attrs['fold'] ? 'true' : 'false'); | ||
return true; | ||
}, | ||
destroy: onDestroy, | ||
}; | ||
@@ -324,0 +216,0 @@ }, |
@@ -35,38 +35,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
const style = (level: number) => | ||
utils.getStyle((_, { css }) => { | ||
const headingMap: Record<number, string> = { | ||
1: css` | ||
font-size: 3rem; | ||
line-height: 3.5rem; | ||
`, | ||
2: css` | ||
font-size: 2.5rem; | ||
line-height: 3rem; | ||
`, | ||
3: css` | ||
font-size: 2.125rem; | ||
line-height: 2.25rem; | ||
`, | ||
4: css` | ||
font-size: 1.75rem; | ||
line-height: 2rem; | ||
`, | ||
5: css` | ||
font-size: 1.5rem; | ||
line-height: 1.5rem; | ||
`, | ||
6: css` | ||
font-size: 1.25rem; | ||
line-height: 1.25rem; | ||
`, | ||
}; | ||
return css` | ||
${headingMap[level] || ''} | ||
margin: 2.5rem 0 !important; | ||
font-weight: 400; | ||
`; | ||
}); | ||
return { | ||
@@ -100,7 +64,3 @@ id, | ||
id: node.attrs['id'] || node.textContent.split(' ').join('-').toLocaleLowerCase(), | ||
class: utils.getClassName( | ||
node.attrs, | ||
`heading h${node.attrs['level']}`, | ||
style(node.attrs['level']), | ||
), | ||
class: utils.getClassName(node.attrs, `heading h${node.attrs['level']}`), | ||
}, | ||
@@ -107,0 +67,0 @@ 0, |
@@ -9,9 +9,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const hr = createNode((utils) => { | ||
const style = utils.getStyle( | ||
(themeTool, { css }) => css` | ||
height: ${themeTool.size.lineWidth}; | ||
background-color: ${themeTool.palette('line')}; | ||
border-width: 0; | ||
`, | ||
); | ||
return { | ||
@@ -22,3 +15,3 @@ id, | ||
parseDOM: [{ tag: 'hr' }], | ||
toDOM: (node) => ['hr', { class: utils.getClassName(node.attrs, id, style) }], | ||
toDOM: (node) => ['hr', { class: utils.getClassName(node.attrs, id) }], | ||
parseMarkdown: { | ||
@@ -25,0 +18,0 @@ match: ({ type }) => type === 'thematicBreak', |
/* Copyright 2021, Milkdown by Mirone. */ | ||
import { createCmd, createCmdKey, themeToolCtx } from '@milkdown/core'; | ||
import type { Icon } from '@milkdown/design-system'; | ||
import { findSelectedNodeOfType, InputRule } from '@milkdown/prose'; | ||
import { commandsCtx, createCmd, createCmdKey, ThemeImageType, ThemeInputChipType } from '@milkdown/core'; | ||
import { EditorView, findSelectedNodeOfType, InputRule, Plugin, PluginKey } from '@milkdown/prose'; | ||
import { createNode } from '@milkdown/utils'; | ||
@@ -12,128 +11,11 @@ | ||
isBlock: boolean; | ||
placeholder: { | ||
loading: string; | ||
empty: string; | ||
failed: string; | ||
placeholder: string; | ||
input: { | ||
placeholder: string; | ||
buttonText?: string; | ||
}; | ||
}; | ||
const key = new PluginKey('MILKDOWN_PLUGIN_IMAGE_INPUT'); | ||
export const image = createNode<string, ImageOptions>((utils, options) => { | ||
const placeholder = { | ||
loading: 'Loading...', | ||
empty: 'Add an Image', | ||
failed: 'Image loads failed', | ||
...(options?.placeholder ?? {}), | ||
}; | ||
const isBlock = options?.isBlock ?? false; | ||
const containerStyle = utils.getStyle( | ||
(themeTool, { css }) => | ||
css` | ||
display: inline-block; | ||
position: relative; | ||
text-align: center; | ||
font-size: 0; | ||
vertical-align: text-bottom; | ||
line-height: 1; | ||
${isBlock | ||
? ` | ||
width: 100%; | ||
margin: 0 auto; | ||
` | ||
: ''} | ||
&.ProseMirror-selectednode::after { | ||
content: ''; | ||
background: ${themeTool.palette('secondary', 0.38)}; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
right: 0; | ||
bottom: 0; | ||
} | ||
img { | ||
max-width: 100%; | ||
height: auto; | ||
object-fit: contain; | ||
margin: 0 2px; | ||
} | ||
.icon, | ||
.placeholder { | ||
display: none; | ||
} | ||
&.system { | ||
width: 100%; | ||
padding: 0 2rem; | ||
img { | ||
width: 0; | ||
height: 0; | ||
display: none; | ||
} | ||
.icon, | ||
.placeholder { | ||
display: inline; | ||
} | ||
box-sizing: border-box; | ||
height: 3rem; | ||
background-color: ${themeTool.palette('background')}; | ||
border-radius: ${themeTool.size.radius}; | ||
display: inline-flex; | ||
gap: 2rem; | ||
justify-content: flex-start; | ||
align-items: center; | ||
.placeholder { | ||
margin: 0; | ||
line-height: 1; | ||
&::before { | ||
content: ''; | ||
font-size: 0.875rem; | ||
color: ${themeTool.palette('neutral', 0.6)}; | ||
} | ||
} | ||
} | ||
&.loading { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.loading}'; | ||
} | ||
} | ||
} | ||
&.empty { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.empty}'; | ||
} | ||
} | ||
} | ||
&.failed { | ||
.placeholder { | ||
&::before { | ||
content: '${placeholder.failed}'; | ||
} | ||
} | ||
} | ||
`, | ||
); | ||
const style = utils.getStyle( | ||
(_, { css }) => | ||
css` | ||
display: inline-block; | ||
margin: 0 auto; | ||
object-fit: contain; | ||
width: 100%; | ||
position: relative; | ||
height: auto; | ||
text-align: center; | ||
`, | ||
); | ||
return { | ||
@@ -154,5 +36,2 @@ id: 'image', | ||
title: { default: null }, | ||
failed: { default: false }, | ||
loading: { default: true }, | ||
width: { default: null }, | ||
}, | ||
@@ -167,4 +46,2 @@ parseDOM: [ | ||
return { | ||
failed: dom.classList.contains('failed'), | ||
loading: dom.classList.contains('loading'), | ||
src: dom.getAttribute('src') || '', | ||
@@ -183,9 +60,3 @@ alt: dom.getAttribute('alt'), | ||
...node.attrs, | ||
class: utils.getClassName( | ||
node.attrs, | ||
id, | ||
node.attrs['failed'] ? 'failed' : '', | ||
node.attrs['loading'] ? 'loading' : '', | ||
style, | ||
), | ||
class: utils.getClassName(node.attrs, id), | ||
}, | ||
@@ -256,114 +127,91 @@ ]; | ||
], | ||
view: (ctx) => (node, view, getPos) => { | ||
const nodeType = node.type; | ||
const createIcon = ctx.get(themeToolCtx).slots.icon; | ||
const container = document.createElement('span'); | ||
container.className = utils.getClassName(node.attrs, id, containerStyle); | ||
view: () => (node) => { | ||
let currNode = node; | ||
const content = document.createElement('img'); | ||
const placeholder = options?.placeholder ?? 'Add an Image'; | ||
const isBlock = options?.isBlock ?? false; | ||
const renderer = utils.themeManager.get<ThemeImageType>('image', { | ||
placeholder, | ||
isBlock, | ||
}); | ||
container.append(content); | ||
let icon = createIcon('image'); | ||
const placeholder = document.createElement('span'); | ||
placeholder.classList.add('placeholder'); | ||
container.append(icon, placeholder); | ||
const setIcon = (name: Icon) => { | ||
const nextIcon = createIcon(name); | ||
container.replaceChild(nextIcon, icon); | ||
icon = nextIcon; | ||
}; | ||
const loadImage = (src: string) => { | ||
container.classList.add('system', 'loading'); | ||
setIcon('loading'); | ||
const img = document.createElement('img'); | ||
img.src = src; | ||
img.onerror = () => { | ||
const pos = getPos(); | ||
if (!pos) return; | ||
const { tr } = view.state; | ||
const _tr = tr.setNodeMarkup(pos, nodeType, { | ||
...node.attrs, | ||
src, | ||
loading: false, | ||
failed: true, | ||
}); | ||
view.dispatch(_tr); | ||
}; | ||
img.onload = () => { | ||
const { tr } = view.state; | ||
const pos = getPos(); | ||
if (!pos) return; | ||
const _tr = tr.setNodeMarkup(pos, nodeType, { | ||
...node.attrs, | ||
width: img.width, | ||
src, | ||
loading: false, | ||
failed: false, | ||
}); | ||
view.dispatch(_tr); | ||
}; | ||
}; | ||
const { src, loading, title, alt, width } = node.attrs; | ||
content.src = src; | ||
content.title = title || alt; | ||
content.alt = alt; | ||
if (width) { | ||
content.width = width; | ||
if (!renderer) { | ||
return {}; | ||
} | ||
if (src.length === 0) { | ||
container.classList.add('system', 'empty'); | ||
setIcon('image'); | ||
} else if (loading) { | ||
loadImage(src); | ||
} | ||
const { dom, onUpdate } = renderer; | ||
onUpdate(currNode); | ||
return { | ||
dom: container, | ||
dom, | ||
update: (updatedNode) => { | ||
if (updatedNode.type.name !== id) return false; | ||
const { src, alt, title, loading, failed, width } = updatedNode.attrs; | ||
content.src = src; | ||
content.alt = alt; | ||
content.title = title || alt; | ||
if (width) { | ||
content.width = width; | ||
} | ||
if (loading) { | ||
loadImage(src); | ||
return true; | ||
} | ||
if (failed) { | ||
container.classList.remove('loading', 'empty'); | ||
container.classList.add('system', 'failed'); | ||
setIcon('brokenImage'); | ||
return true; | ||
} | ||
if (src.length > 0) { | ||
container.classList.remove('system', 'empty', 'loading'); | ||
return true; | ||
} | ||
currNode = updatedNode; | ||
onUpdate(currNode); | ||
container.classList.add('system', 'empty'); | ||
setIcon('image'); | ||
return true; | ||
}, | ||
selectNode: () => { | ||
container.classList.add('ProseMirror-selectednode'); | ||
dom.classList.add('ProseMirror-selectednode'); | ||
}, | ||
deselectNode: () => { | ||
container.classList.remove('ProseMirror-selectednode'); | ||
dom.classList.remove('ProseMirror-selectednode'); | ||
}, | ||
}; | ||
}, | ||
prosePlugins: (type, ctx) => { | ||
const inputChipRenderer = utils.themeManager.get<ThemeInputChipType>('input-chip', { | ||
placeholder: options?.input?.placeholder ?? 'Input Image Link', | ||
buttonText: options?.input?.buttonText, | ||
onUpdate: (value) => { | ||
ctx.get(commandsCtx).call(ModifyImage, value); | ||
}, | ||
}); | ||
const shouldDisplay = (view: EditorView) => { | ||
return Boolean(type && findSelectedNodeOfType(view.state.selection, type)); | ||
}; | ||
const getCurrentLink = (view: EditorView) => { | ||
const result = findSelectedNodeOfType(view.state.selection, type); | ||
if (!result) return; | ||
const value = result.node.attrs['src']; | ||
return value; | ||
}; | ||
const renderByView = (view: EditorView) => { | ||
if (!view.editable) { | ||
return; | ||
} | ||
const display = shouldDisplay(view); | ||
if (display) { | ||
inputChipRenderer.show(view); | ||
inputChipRenderer.update(getCurrentLink(view)); | ||
} else { | ||
inputChipRenderer.hide(); | ||
} | ||
}; | ||
return [ | ||
new Plugin({ | ||
key, | ||
view: (editorView) => { | ||
inputChipRenderer.init(editorView); | ||
renderByView(editorView); | ||
return { | ||
update: (view, prevState) => { | ||
const isEqualSelection = | ||
prevState?.doc.eq(view.state.doc) && prevState.selection.eq(view.state.selection); | ||
if (isEqualSelection) return; | ||
renderByView(view); | ||
}, | ||
destroy: () => { | ||
inputChipRenderer.destroy(); | ||
}, | ||
}; | ||
}, | ||
}), | ||
]; | ||
}, | ||
}; | ||
}); |
@@ -16,57 +16,38 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const listItem = createNode<Keys>((utils) => { | ||
const style = utils.getStyle( | ||
(themeTool, { css }) => | ||
css` | ||
&, | ||
& > * { | ||
margin: 0.5rem 0; | ||
} | ||
&, | ||
li { | ||
&::marker { | ||
color: ${themeTool.palette('primary')}; | ||
} | ||
} | ||
`, | ||
); | ||
return { | ||
id, | ||
schema: () => ({ | ||
group: 'listItem', | ||
content: 'paragraph block*', | ||
defining: true, | ||
parseDOM: [{ tag: 'li' }], | ||
toDOM: (node) => ['li', { class: utils.getClassName(node.attrs, 'list-item', style) }, 0], | ||
parseMarkdown: { | ||
match: ({ type, checked }) => type === 'listItem' && checked === null, | ||
runner: (state, node, type) => { | ||
state.openNode(type); | ||
state.next(node.children); | ||
state.closeNode(); | ||
}, | ||
export const listItem = createNode<Keys>((utils) => ({ | ||
id, | ||
schema: () => ({ | ||
group: 'listItem', | ||
content: 'paragraph block*', | ||
defining: true, | ||
parseDOM: [{ tag: 'li' }], | ||
toDOM: (node) => ['li', { class: utils.getClassName(node.attrs, 'list-item') }, 0], | ||
parseMarkdown: { | ||
match: ({ type, checked }) => type === 'listItem' && checked === null, | ||
runner: (state, node, type) => { | ||
state.openNode(type); | ||
state.next(node.children); | ||
state.closeNode(); | ||
}, | ||
toMarkdown: { | ||
match: (node) => node.type.name === id, | ||
runner: (state, node) => { | ||
state.openNode('listItem'); | ||
state.next(node.content); | ||
state.closeNode(); | ||
}, | ||
}, | ||
toMarkdown: { | ||
match: (node) => node.type.name === id, | ||
runner: (state, node) => { | ||
state.openNode('listItem'); | ||
state.next(node.content); | ||
state.closeNode(); | ||
}, | ||
}), | ||
inputRules: (nodeType) => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)], | ||
commands: (nodeType) => [ | ||
createCmd(SplitListItem, () => splitListItem(nodeType)), | ||
createCmd(SinkListItem, () => sinkListItem(nodeType)), | ||
createCmd(LiftListItem, () => liftListItem(nodeType)), | ||
], | ||
shortcuts: { | ||
[SupportedKeys.NextListItem]: createShortcut(SplitListItem, 'Enter'), | ||
[SupportedKeys.SinkListItem]: createShortcut(SinkListItem, 'Mod-]'), | ||
[SupportedKeys.LiftListItem]: createShortcut(LiftListItem, 'Mod-['), | ||
}, | ||
}; | ||
}); | ||
}), | ||
inputRules: (nodeType) => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)], | ||
commands: (nodeType) => [ | ||
createCmd(SplitListItem, () => splitListItem(nodeType)), | ||
createCmd(SinkListItem, () => sinkListItem(nodeType)), | ||
createCmd(LiftListItem, () => liftListItem(nodeType)), | ||
], | ||
shortcuts: { | ||
[SupportedKeys.NextListItem]: createShortcut(SplitListItem, 'Enter'), | ||
[SupportedKeys.SinkListItem]: createShortcut(SinkListItem, 'Mod-]'), | ||
[SupportedKeys.LiftListItem]: createShortcut(LiftListItem, 'Mod-['), | ||
}, | ||
})); |
@@ -14,10 +14,2 @@ /* Copyright 2021, Milkdown by Mirone. */ | ||
export const paragraph = createNode<Keys>((utils) => { | ||
const style = utils.getStyle((_, { css }) => { | ||
return css` | ||
font-size: 1rem; | ||
line-height: 1.5; | ||
letter-spacing: 0.5px; | ||
`; | ||
}); | ||
return { | ||
@@ -29,3 +21,3 @@ id, | ||
parseDOM: [{ tag: 'p' }], | ||
toDOM: (node) => ['p', { class: utils.getClassName(node.attrs, id, style) }, 0], | ||
toDOM: (node) => ['p', { class: utils.getClassName(node.attrs, id) }, 0], | ||
parseMarkdown: { | ||
@@ -32,0 +24,0 @@ match: (node) => node.type === 'paragraph', |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
2
87
193236
72
2856
2
+ Added@milkdown/core@6.5.4(transitive)
+ Added@milkdown/ctx@6.5.4(transitive)
+ Added@milkdown/design-system@6.5.4(transitive)
+ Added@milkdown/exception@6.0.0-next.06.5.4(transitive)
+ Added@milkdown/prose@6.5.4(transitive)
+ Added@milkdown/transformer@6.5.4(transitive)
+ Added@milkdown/utils@6.0.0-next.0(transitive)
- Removed@milkdown/core@5.5.0(transitive)
- Removed@milkdown/ctx@5.5.0(transitive)
- Removed@milkdown/design-system@5.5.0(transitive)
- Removed@milkdown/exception@5.5.0(transitive)
- Removed@milkdown/prose@5.5.0(transitive)
- Removed@milkdown/transformer@5.5.0(transitive)
- Removed@milkdown/utils@5.5.0(transitive)
- Removed@types/prosemirror-commands@1.3.0(transitive)
- Removed@types/prosemirror-dropcursor@1.5.0(transitive)
- Removed@types/prosemirror-gapcursor@1.3.0(transitive)
- Removed@types/prosemirror-history@1.3.0(transitive)
- Removed@types/prosemirror-inputrules@1.2.0(transitive)
- Removed@types/prosemirror-keymap@1.2.0(transitive)
- Removed@types/prosemirror-model@1.17.0(transitive)
- Removed@types/prosemirror-schema-list@1.2.0(transitive)
- Removed@types/prosemirror-state@1.4.0(transitive)
- Removed@types/prosemirror-transform@1.5.0(transitive)
- Removed@types/prosemirror-view@1.24.0(transitive)
- Removedprosemirror-tables@1.6.1(transitive)
Updated@milkdown/utils@6.0.0-next.0