@livingdocs/editable.js 5.1.0 → 5.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editable.js +1 -1
- package/dist/editable.js.map +1 -1
- package/package.json +6 -6
- package/src/dispatcher.js +1 -1
- package/src/smartQuotes.js +20 -13
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livingdocs/editable.js",
|
|
3
3
|
"description": "Friendly contenteditable API",
|
|
4
|
-
"version": "5.1.
|
|
4
|
+
"version": "5.1.2",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/runtime": "^7.16.7",
|
|
7
7
|
"lodash-es": "^4.17.21"
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"@babel/preset-env": "^7.16.11",
|
|
14
14
|
"@babel/preset-react": "^7.16.7",
|
|
15
15
|
"@eslint/compat": "^1.1.0",
|
|
16
|
-
"babel-loader": "^
|
|
16
|
+
"babel-loader": "^10.0.0",
|
|
17
17
|
"babel-plugin-add-module-exports": "^1.0.4",
|
|
18
18
|
"babel-plugin-istanbul": "^7.0.0",
|
|
19
19
|
"chai": "^5.0.0",
|
|
20
20
|
"css-loader": "^7.0.0",
|
|
21
21
|
"eslint": "^9.6.0",
|
|
22
22
|
"eslint-plugin-react": "^7.34.3",
|
|
23
|
-
"globals": "^
|
|
23
|
+
"globals": "^16.0.0",
|
|
24
24
|
"karma": "^6.3.13",
|
|
25
25
|
"karma-chrome-launcher": "^3.1.0",
|
|
26
26
|
"karma-coverage": "^2.1.0",
|
|
@@ -82,11 +82,11 @@
|
|
|
82
82
|
"isCi": true,
|
|
83
83
|
"name": "Drone",
|
|
84
84
|
"service": "drone",
|
|
85
|
-
"commit": "
|
|
86
|
-
"build": "
|
|
85
|
+
"commit": "353179e4f72107cca78fac6d232921a4c42f9815",
|
|
86
|
+
"build": "2012",
|
|
87
87
|
"branch": "master",
|
|
88
88
|
"isPr": false,
|
|
89
89
|
"slug": "livingdocsIO/editable.js",
|
|
90
|
-
"date": "2025-
|
|
90
|
+
"date": "2025-03-20T07:08:54.260Z"
|
|
91
91
|
}
|
|
92
92
|
}
|
package/src/dispatcher.js
CHANGED
package/src/smartQuotes.js
CHANGED
|
@@ -5,24 +5,27 @@ export const shouldApplySmartQuotes = (config, target) => {
|
|
|
5
5
|
return !!smartQuotes && isValidQuotePairConfig(quotes) && isValidQuotePairConfig(singleQuotes) && target.isContentEditable
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
const isDoubleQuote = (char) => /^[«»"“”„]$/.test(char)
|
|
9
|
-
const isSingleQuote = (char) => /^[‘’‹›‚']$/.test(char)
|
|
10
|
-
const isApostrophe = (char) => /^[’']$/.test(char)
|
|
11
|
-
const isWhitespace = (char) => /^\s$/.test(char)
|
|
12
|
-
const isSeparatorOrWhitespace = (char) => /\s|[>\-–—]/.test(char)
|
|
8
|
+
export const isDoubleQuote = (char) => /^[«»"“”„]$/.test(char)
|
|
9
|
+
export const isSingleQuote = (char) => /^[‘’‹›‚']$/.test(char)
|
|
10
|
+
export const isApostrophe = (char) => /^[’']$/.test(char)
|
|
11
|
+
export const isWhitespace = (char) => /^\s$/.test(char)
|
|
12
|
+
export const isSeparatorOrWhitespace = (char) => /\s|[>\-–—]/.test(char)
|
|
13
13
|
|
|
14
14
|
const shouldBeOpeningQuote = (text, indexCharBefore) => indexCharBefore < 0 || isSeparatorOrWhitespace(text[indexCharBefore])
|
|
15
15
|
const shouldBeClosingQuote = (text, indexCharBefore) => !!text[indexCharBefore] && !isSeparatorOrWhitespace(text[indexCharBefore])
|
|
16
16
|
const hasCharAfter = (textArr, indexCharAfter) => !!textArr[indexCharAfter] && !isWhitespace(textArr[indexCharAfter])
|
|
17
|
+
const shouldBeSingleOpeningQuote = (text, indexCharBefore) => !!text[indexCharBefore] && isDoubleQuote(text[indexCharBefore])
|
|
17
18
|
|
|
18
|
-
const replaceQuote = (range, index, quoteType) => {
|
|
19
|
-
const startContainer = range
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
export const replaceQuote = (range, index, quoteType) => {
|
|
20
|
+
const startContainer = range?.startContainer
|
|
21
|
+
const nodeValue = startContainer?.nodeValue
|
|
22
|
+
if (!nodeValue) {
|
|
23
|
+
return null
|
|
22
24
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
const newText = `${nodeValue.substring(0, index)}${quoteType}${nodeValue.substring(index + 1)}`
|
|
26
|
+
const newTextNode = document.createTextNode(newText)
|
|
27
|
+
startContainer.replaceWith(newTextNode)
|
|
28
|
+
return newTextNode
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
const hasSingleOpeningQuote = (textArr, offset, singleOpeningQuote) => {
|
|
@@ -54,7 +57,11 @@ export const applySmartQuotes = (range, config, char, target, cursorOffset) => {
|
|
|
54
57
|
const textArr = [...range.startContainer.textContent]
|
|
55
58
|
let newTextNode
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
// Special case for a single quote following a double quote,
|
|
61
|
+
// which should be transformed into a single opening quote
|
|
62
|
+
if (isCharSingleQuote && shouldBeSingleOpeningQuote(textArr, offset - 2)) {
|
|
63
|
+
newTextNode = replaceQuote(range, offset - 1, singleQuotes[0])
|
|
64
|
+
} else if (shouldBeClosingQuote(textArr, offset - 2)) {
|
|
58
65
|
if (isCharSingleQuote) {
|
|
59
66
|
// Don't transform apostrophes
|
|
60
67
|
if (hasCharAfter(textArr, offset)) {
|