@stackoverflow/stacks-editor
Advanced tools
Comparing version 0.8.0 to 0.8.1
@@ -43,2 +43,8 @@ import { EditorState, Transaction } from "prosemirror-state"; | ||
export declare function insertCommonmarkTableCommand(state: EditorState, dispatch: (tr: Transaction) => void): boolean; | ||
/** | ||
* Inserts a horizontal rule at the cursor | ||
* @param state The current editor state | ||
* @param dispatch the dispatch function used to dispatch the transaction, set to "null" if you don't want to dispatch | ||
*/ | ||
export declare function insertCommonmarkHorizontalRuleCommand(state: EditorState, dispatch: (tr: Transaction) => void): boolean; | ||
declare function indentBlockCommand(): boolean; | ||
@@ -60,3 +66,2 @@ declare function unIndentBlockCommand(): boolean; | ||
export declare const unorderedListCommand: MenuCommand; | ||
export declare const insertCommonmarkHorizontalRuleCommand: MenuCommand; | ||
export declare const insertCodeblockCommand: MenuCommand; | ||
@@ -63,0 +68,0 @@ export declare const spoilerCommand: MenuCommand; |
@@ -437,2 +437,36 @@ import { TextSelection } from "prosemirror-state"; | ||
} | ||
/** | ||
* Inserts a horizontal rule at the cursor | ||
* @param state The current editor state | ||
* @param dispatch the dispatch function used to dispatch the transaction, set to "null" if you don't want to dispatch | ||
*/ | ||
export function insertCommonmarkHorizontalRuleCommand(state, dispatch) { | ||
// figure out how many leading newlines we need to add | ||
// adding only a single newline after text will result in the thematic break | ||
// being parsed as an setext heading; e.g. header1\n--- | ||
const precedingText = state.doc.cut(0, state.selection.from).textContent; | ||
const lastNewlineIdx = precedingText.lastIndexOf("\n"); | ||
const currentLine = precedingText.slice(lastNewlineIdx + 1); | ||
// check the previous line as well | ||
let prevLine = null; | ||
if (lastNewlineIdx > -1) { | ||
const prevNewlineIdx = precedingText.lastIndexOf("\n", lastNewlineIdx - 1); | ||
// even if no additional newline is found, we can assume an index of (-1 + 1), which is the beginning of the text | ||
prevLine = precedingText.slice(prevNewlineIdx + 1, lastNewlineIdx); | ||
} | ||
let newlines; | ||
if (!precedingText || (!prevLine && !currentLine)) { | ||
// beginning of doc or multiple empty lines - no newlines | ||
newlines = ""; | ||
} | ||
else if (!currentLine) { | ||
// no text in current line - one newline | ||
newlines = "\n"; | ||
} | ||
else { | ||
// text in current line - two newlines | ||
newlines = "\n\n"; | ||
} | ||
return insertRawTextCommand(newlines + "---\n", 4, 4)(state, dispatch); | ||
} | ||
//TODO | ||
@@ -476,3 +510,2 @@ function indentBlockCommand() { | ||
export const unorderedListCommand = setBlockTypeCommand("-"); | ||
export const insertCommonmarkHorizontalRuleCommand = insertRawTextCommand("\n---\n"); | ||
export const insertCodeblockCommand = blockWrapInCommand("```"); | ||
@@ -479,0 +512,0 @@ export const spoilerCommand = setBlockTypeCommand(">!"); |
@@ -28,3 +28,3 @@ import { history } from "prosemirror-history"; | ||
this.editorView = new EditorView((node) => { | ||
node.classList.add(...(this.options.classList || [])); | ||
this.setTargetNodeAttributes(node, this.options); | ||
target.appendChild(node); | ||
@@ -31,0 +31,0 @@ }, { |
@@ -49,3 +49,3 @@ import { history } from "prosemirror-history"; | ||
this.editorView = new EditorView((node) => { | ||
node.classList.add(...(this.options.classList || [])); | ||
this.setTargetNodeAttributes(node, this.options); | ||
target.appendChild(node); | ||
@@ -52,0 +52,0 @@ }, { |
@@ -89,1 +89,9 @@ import { Command, EditorState } from "prosemirror-state"; | ||
}; | ||
/** | ||
* Sets attributes from an object onto an html element; | ||
* style, class* and on* attributes will be ignored; | ||
* @param el The element to set the attributes on | ||
* @param attrs The key/value attributes to set onto the element | ||
* @internal | ||
*/ | ||
export declare function setAttributesOnElement(el: HTMLElement, attrs: Record<string, unknown>): void; |
import { escapeHtml } from "markdown-it/lib/common/utils"; | ||
import { error } from "./logger"; | ||
/** | ||
@@ -236,1 +237,30 @@ * Recursively deep merges two objects into a new object, leaving the original two untouched | ||
} | ||
/** | ||
* Kebab cases a string e.g. "backgroundColor" to "background-color" | ||
* @param str input string | ||
*/ | ||
function toKebabCase(str) { | ||
return str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()); | ||
} | ||
/** | ||
* Sets attributes from an object onto an html element; | ||
* style, class* and on* attributes will be ignored; | ||
* @param el The element to set the attributes on | ||
* @param attrs The key/value attributes to set onto the element | ||
* @internal | ||
*/ | ||
export function setAttributesOnElement(el, attrs) { | ||
Object.entries(attrs).forEach(([key, val]) => { | ||
if (key === "style" || | ||
key.startsWith("class") || | ||
key.startsWith("on")) { | ||
error("setAttributesOnElement", `Setting the "${key}" attribute is not supported`); | ||
return; | ||
} | ||
if (val !== false) { | ||
// set falsy values, but don't set properties that are explicitly false | ||
// otherwise, use setAttribute to set the string representation | ||
el.setAttribute(toKebabCase(key), val === true ? "" : String(val)); | ||
} | ||
}); | ||
} |
@@ -14,2 +14,10 @@ import type { Node } from "prosemirror-model"; | ||
classList?: string[]; | ||
/** | ||
* Attributes to add to the editor target element; | ||
* attributes with a value of `true` will be set without a value; | ||
* likewise, attributes with a value of `false` will not be set at all; | ||
* camelCased keys will be translated to kebab-case | ||
* e.g. "dataFooBar" will become "data-foo-bar" | ||
*/ | ||
elementAttributes?: Record<string, unknown>; | ||
/** The url to where the "Help" button should lead to */ | ||
@@ -101,2 +109,8 @@ editorHelpLink?: string; | ||
/** | ||
* Sets all attributes on the target contenteditable element | ||
* @param el The node to set the attributes on | ||
* @param options The options passed to the editor | ||
*/ | ||
protected setTargetNodeAttributes(el: HTMLElement, options: CommonViewOptions): void; | ||
/** | ||
* Parses a string containing markdown into a Node | ||
@@ -103,0 +117,0 @@ * @param content The markdown string to parse |
@@ -1,2 +0,2 @@ | ||
import { stackOverflowValidateLink } from "./utils"; | ||
import { setAttributesOnElement, stackOverflowValidateLink } from "./utils"; | ||
/** Describes each distinct editor type the StacksEditor handles */ | ||
@@ -47,2 +47,16 @@ export var EditorType; | ||
} | ||
/** | ||
* Sets all attributes on the target contenteditable element | ||
* @param el The node to set the attributes on | ||
* @param options The options passed to the editor | ||
*/ | ||
setTargetNodeAttributes(el, options) { | ||
// add in the passed in classes | ||
el.classList.add(...(options.classList || [])); | ||
// add some a11y attributes for screen readers | ||
el.setAttribute("role", "textbox"); | ||
el.setAttribute("aria-multiline", "true"); | ||
// add the rest of the attributes passed in via options | ||
setAttributesOnElement(el, options.elementAttributes || {}); | ||
} | ||
} |
@@ -61,3 +61,2 @@ import { CommonmarkEditor } from "../commonmark/editor"; | ||
"s-prose", | ||
//"s-prose", //TODO re-add once s-prose is the default in Core and we can hardcode here | ||
// in case this needs to be reference by outside code or e2e tests | ||
@@ -82,2 +81,3 @@ "js-editor", | ||
], | ||
elementAttributes: {}, | ||
parserFeatures: RichTextEditor.defaultOptions.parserFeatures, | ||
@@ -84,0 +84,0 @@ commonmarkOptions: { |
{ | ||
"name": "@stackoverflow/stacks-editor", | ||
"version": "0.8.0", | ||
"version": "0.8.1", | ||
"description": "", | ||
@@ -50,3 +50,3 @@ "repository": { | ||
"@commitlint/config-conventional": "^17.1.0", | ||
"@playwright/test": "^1.25.2", | ||
"@playwright/test": "^1.26.0", | ||
"@stackoverflow/commitlint-config": "^1.0.0", | ||
@@ -56,9 +56,9 @@ "@stackoverflow/eslint-config": "^1.0.0", | ||
"@stackoverflow/tsconfig": "^1.0.0", | ||
"@types/jest": "^29.0.2", | ||
"@typescript-eslint/eslint-plugin": "^5.37.0", | ||
"@typescript-eslint/parser": "^5.37.0", | ||
"@types/jest": "^29.0.3", | ||
"@typescript-eslint/eslint-plugin": "^5.38.1", | ||
"@typescript-eslint/parser": "^5.38.1", | ||
"clean-webpack-plugin": "^4.0.0", | ||
"css-loader": "^6.7.1", | ||
"cssnano": "^5.1.13", | ||
"eslint": "^8.23.1", | ||
"eslint": "^8.24.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
@@ -68,3 +68,3 @@ "eslint-plugin-jest": "^27.0.4", | ||
"highlight.js": "^11.6.0", | ||
"html-loader": "^4.1.0", | ||
"html-loader": "^4.2.0", | ||
"html-webpack-plugin": "^5.5.0", | ||
@@ -83,4 +83,4 @@ "husky": "^8.0.1", | ||
"standard-version": "^9.5.0", | ||
"ts-jest": "^29.0.1", | ||
"ts-loader": "^9.3.1", | ||
"ts-jest": "^29.0.2", | ||
"ts-loader": "^9.4.1", | ||
"typescript": "^4.8.3", | ||
@@ -90,13 +90,13 @@ "webpack": "^5.74.0", | ||
"webpack-cli": "^4.10.0", | ||
"webpack-dev-server": "^4.11.0", | ||
"webpack-dev-server": "^4.11.1", | ||
"webpack-merge": "^5.8.0" | ||
}, | ||
"dependencies": { | ||
"@lezer/highlight": "^1.0.0", | ||
"@lezer/markdown": "^1.0.1", | ||
"@stackoverflow/stacks": "^1.3.5", | ||
"@lezer/highlight": "^1.1.1", | ||
"@lezer/markdown": "^1.0.2", | ||
"@stackoverflow/stacks": "^1.3.6", | ||
"@stackoverflow/stacks-icons": "^3.0.5", | ||
"@types/markdown-it": "12.2.3", | ||
"markdown-it": "^13.0.1", | ||
"orderedmap": "^2.0.0", | ||
"orderedmap": "^2.1.0", | ||
"prosemirror-commands": "^1.3.1", | ||
@@ -114,3 +114,3 @@ "prosemirror-highlightjs": "^0.9.1", | ||
"prosemirror-transform": "^1.7.0", | ||
"prosemirror-view": "^1.28.0" | ||
"prosemirror-view": "^1.28.2" | ||
}, | ||
@@ -117,0 +117,0 @@ "peerDependencies": { |
Sorry, the diff of this file is too big to display
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
965025
12462
Updated@lezer/highlight@^1.1.1
Updated@lezer/markdown@^1.0.2
Updated@stackoverflow/stacks@^1.3.6
Updatedorderedmap@^2.1.0
Updatedprosemirror-view@^1.28.2