y-textarea
Advanced tools
Comparing version 0.1.1 to 0.2.0
@@ -0,5 +1,8 @@ | ||
import { options } from './y-textarea-options'; | ||
import * as Y from 'yjs'; | ||
export declare class TextAreaBinding { | ||
constructor(yText: Y.Text, textField: HTMLTextAreaElement | HTMLInputElement); | ||
private _cursors?; | ||
constructor(yText: Y.Text, textField: HTMLTextAreaElement | HTMLInputElement, options?: options); | ||
private createRange; | ||
rePositionCursors(): void; | ||
} |
import * as Y from "yjs"; | ||
import diff from "fast-diff"; | ||
var textareaCaret = { exports: {} }; | ||
(function(module) { | ||
(function() { | ||
var properties = [ | ||
"direction", | ||
"boxSizing", | ||
"width", | ||
"height", | ||
"overflowX", | ||
"overflowY", | ||
"borderTopWidth", | ||
"borderRightWidth", | ||
"borderBottomWidth", | ||
"borderLeftWidth", | ||
"borderStyle", | ||
"paddingTop", | ||
"paddingRight", | ||
"paddingBottom", | ||
"paddingLeft", | ||
"fontStyle", | ||
"fontVariant", | ||
"fontWeight", | ||
"fontStretch", | ||
"fontSize", | ||
"fontSizeAdjust", | ||
"lineHeight", | ||
"fontFamily", | ||
"textAlign", | ||
"textTransform", | ||
"textIndent", | ||
"textDecoration", | ||
"letterSpacing", | ||
"wordSpacing", | ||
"tabSize", | ||
"MozTabSize" | ||
]; | ||
var isBrowser = typeof window !== "undefined"; | ||
var isFirefox = isBrowser && window.mozInnerScreenX != null; | ||
function getCaretCoordinates2(element, position, options) { | ||
if (!isBrowser) { | ||
throw new Error("textarea-caret-position#getCaretCoordinates should only be called in a browser"); | ||
} | ||
var debug = options && options.debug || false; | ||
if (debug) { | ||
var el = document.querySelector("#input-textarea-caret-position-mirror-div"); | ||
if (el) | ||
el.parentNode.removeChild(el); | ||
} | ||
var div = document.createElement("div"); | ||
div.id = "input-textarea-caret-position-mirror-div"; | ||
document.body.appendChild(div); | ||
var style = div.style; | ||
var computed = window.getComputedStyle ? window.getComputedStyle(element) : element.currentStyle; | ||
var isInput = element.nodeName === "INPUT"; | ||
style.whiteSpace = "pre-wrap"; | ||
if (!isInput) | ||
style.wordWrap = "break-word"; | ||
style.position = "absolute"; | ||
if (!debug) | ||
style.visibility = "hidden"; | ||
properties.forEach(function(prop) { | ||
if (isInput && prop === "lineHeight") { | ||
style.lineHeight = computed.height; | ||
} else { | ||
style[prop] = computed[prop]; | ||
} | ||
}); | ||
if (isFirefox) { | ||
if (element.scrollHeight > parseInt(computed.height)) | ||
style.overflowY = "scroll"; | ||
} else { | ||
style.overflow = "hidden"; | ||
} | ||
div.textContent = element.value.substring(0, position); | ||
if (isInput) | ||
div.textContent = div.textContent.replace(/\s/g, "\xA0"); | ||
var span = document.createElement("span"); | ||
span.textContent = element.value.substring(position) || "."; | ||
div.appendChild(span); | ||
var coordinates = { | ||
top: span.offsetTop + parseInt(computed["borderTopWidth"]), | ||
left: span.offsetLeft + parseInt(computed["borderLeftWidth"]), | ||
height: parseInt(computed["lineHeight"]) | ||
}; | ||
if (debug) { | ||
span.style.backgroundColor = "#aaa"; | ||
} else { | ||
document.body.removeChild(div); | ||
} | ||
return coordinates; | ||
} | ||
{ | ||
module.exports = getCaretCoordinates2; | ||
} | ||
})(); | ||
})(textareaCaret); | ||
var getCaretCoordinates = textareaCaret.exports; | ||
function getOverlap(rectangle1, rectangle2) { | ||
const intersectionX1 = Math.max(rectangle1.x, rectangle2.x); | ||
const intersectionX2 = Math.min(rectangle1.x + rectangle1.width, rectangle2.x + rectangle2.width); | ||
if (intersectionX2 < intersectionX1) { | ||
return null; | ||
} | ||
const intersectionY1 = Math.max(rectangle1.y, rectangle2.y); | ||
const intersectionY2 = Math.min(rectangle1.y + rectangle1.height, rectangle2.y + rectangle2.height); | ||
if (intersectionY2 < intersectionY1) { | ||
return null; | ||
} | ||
return new Rectangle(intersectionX1, intersectionY1, intersectionX2 - intersectionX1, intersectionY2 - intersectionY1); | ||
} | ||
class Rectangle { | ||
constructor(x, y, width, height) { | ||
this.x = x; | ||
this.y = y; | ||
this.width = width; | ||
this.height = height; | ||
} | ||
get area() { | ||
return this.width * this.height; | ||
} | ||
} | ||
var rectangleOverlap = getOverlap; | ||
const events = [ | ||
"keyup", | ||
"mouseup", | ||
"touchstart", | ||
"paste", | ||
"cut", | ||
"selectend" | ||
]; | ||
class Cursor { | ||
constructor(fontSize, cssColor, name) { | ||
Object.defineProperty(this, "_div", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "_nameDiv", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "_color", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "_fontSize", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "_selectedIndex", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this._selectedIndex = { start: -1, end: -1 }; | ||
this._fontSize = fontSize; | ||
this._color = cssColor; | ||
this._div = document.createElement("div"); | ||
this._div.style.position = "absolute"; | ||
this._div.style.backgroundColor = `rgba(${cssColor.r}, ${cssColor.g}, ${cssColor.b}, 0.4)`; | ||
this._div.style.height = fontSize; | ||
this._div.style.width = "1px"; | ||
this._div.style.display = "none"; | ||
this._div.classList.add("selectedText"); | ||
document.body.appendChild(this._div); | ||
if (name !== void 0) { | ||
this._nameDiv = document.createElement("div"); | ||
this._nameDiv.style.position = "absolute"; | ||
this._nameDiv.style.display = "none"; | ||
this._nameDiv.style.backgroundColor = `rgba(${cssColor.r}, ${cssColor.g}, ${cssColor.b}, 1.0)`; | ||
this._nameDiv.classList.add("nameTag"); | ||
this._nameDiv.innerHTML = name; | ||
document.body.appendChild(this._nameDiv); | ||
} | ||
} | ||
show() { | ||
this._div.style.display = "block"; | ||
if (this._nameDiv) | ||
this._nameDiv.style.display = "block"; | ||
} | ||
hide() { | ||
this._div.style.display = "none"; | ||
if (this._nameDiv) | ||
this._nameDiv.style.display = "none"; | ||
} | ||
setPosition(start, end) { | ||
this._selectedIndex = { start, end }; | ||
} | ||
setWidth(width) { | ||
this._div.style.width = width + "px"; | ||
if (width === 1) { | ||
this._div.style.backgroundColor = `rgba(${this._color.r}, ${this._color.g}, ${this._color.b}, 1.0)`; | ||
} else { | ||
this._div.style.backgroundColor = `rgba(${this._color.r}, ${this._color.g}, ${this._color.b}, 0.4)`; | ||
} | ||
} | ||
rePosition(textFeild) { | ||
if (this._selectedIndex.start === -1 || this._selectedIndex.end === -1) | ||
return; | ||
const startCoordinates = getCaretCoordinates(textFeild, this._selectedIndex.start); | ||
const screenSpaceTop = textFeild.offsetTop - textFeild.scrollTop + startCoordinates.top; | ||
const screenSpaceLeft = textFeild.offsetLeft - textFeild.scrollLeft + startCoordinates.left; | ||
let width = 1; | ||
let height = 0; | ||
if (this._selectedIndex.start !== this._selectedIndex.end) { | ||
let endCoordinates = getCaretCoordinates(textFeild, this._selectedIndex.end); | ||
width = endCoordinates.left - startCoordinates.left; | ||
height = endCoordinates.top - startCoordinates.top; | ||
if (height !== 0) | ||
width = 1; | ||
} | ||
const areaScreenSpace = { | ||
x: textFeild.offsetLeft, | ||
y: textFeild.offsetTop, | ||
width: textFeild.clientWidth, | ||
height: textFeild.clientHeight | ||
}; | ||
const cursorScreenSpace = { | ||
x: screenSpaceLeft, | ||
y: screenSpaceTop, | ||
width, | ||
height: parseInt(this._fontSize) | ||
}; | ||
const overlap = rectangleOverlap(areaScreenSpace, cursorScreenSpace); | ||
if (!overlap) { | ||
this.hide(); | ||
return; | ||
} | ||
this._div.style.top = overlap.y + "px"; | ||
this._div.style.left = overlap.x + "px"; | ||
this.setWidth(overlap.width); | ||
this.show(); | ||
if (this._nameDiv) { | ||
this._nameDiv.style.top = overlap.y + parseInt(this._fontSize) + "px"; | ||
this._nameDiv.style.left = overlap.x + "px"; | ||
} | ||
} | ||
destroy() { | ||
document.body.removeChild(this._div); | ||
if (this._nameDiv) | ||
document.body.removeChild(this._nameDiv); | ||
} | ||
} | ||
class TextAreaCursors { | ||
constructor(yText, textField, options) { | ||
Object.defineProperty(this, "_cursors", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: /* @__PURE__ */ new Map() | ||
}); | ||
Object.defineProperty(this, "_areaID", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: "" | ||
}); | ||
Object.defineProperty(this, "_textField", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this._areaID = (TextAreaCursors.areaIDCounter++).toString(); | ||
this._textField = textField; | ||
if (textField.selectionStart === null || textField.selectionEnd === null) { | ||
throw new Error("unSupported Input type"); | ||
} | ||
const doc = yText.doc; | ||
if (doc === null) { | ||
throw new Error("Missing doc on yText"); | ||
} | ||
options.awareness.on("update", (event) => { | ||
if (event.removed.length != 0) { | ||
for (const id of event.removed) { | ||
if (this._cursors.has(id)) { | ||
const cursor = this._cursors.get(id); | ||
cursor == null ? void 0 : cursor.destroy(); | ||
this._cursors.delete(id); | ||
} | ||
} | ||
} | ||
const fontSize = getComputedStyle(textField).getPropertyValue("font-size"); | ||
const changes = options.awareness.getStates(); | ||
for (const [clientID, change] of changes.entries()) { | ||
if (clientID === options.awareness.clientID) | ||
continue; | ||
const user = change[this._areaID]; | ||
if (user === void 0) | ||
continue; | ||
const encodedStart = user["start"]; | ||
const encodedEnd = user["end"]; | ||
const name = user["name"]; | ||
const color = user["color"]; | ||
const selection = user["selection"]; | ||
if (!this._cursors.has(clientID)) { | ||
this._cursors.set(clientID, new Cursor(fontSize, color, name)); | ||
} | ||
const cursorMarker = this._cursors.get(clientID); | ||
if (!selection) { | ||
cursorMarker == null ? void 0 : cursorMarker.setPosition(-1, -1); | ||
cursorMarker == null ? void 0 : cursorMarker.hide(); | ||
continue; | ||
} | ||
if (encodedStart === void 0 || encodedEnd === void 0) | ||
continue; | ||
const start = Y.createAbsolutePositionFromRelativePosition(JSON.parse(encodedStart), doc); | ||
const end = Y.createAbsolutePositionFromRelativePosition(JSON.parse(encodedEnd), doc); | ||
if (start === null || end === null) { | ||
cursorMarker == null ? void 0 : cursorMarker.hide(); | ||
continue; | ||
} | ||
cursorMarker == null ? void 0 : cursorMarker.setPosition(start.index, end.index); | ||
cursorMarker == null ? void 0 : cursorMarker.rePosition(textField); | ||
} | ||
}); | ||
for (const event of events) { | ||
textField.addEventListener(event, () => { | ||
const start = textField.selectionStart; | ||
const end = textField.selectionEnd; | ||
const startRel = Y.createRelativePositionFromTypeIndex(yText, start); | ||
const endRel = Y.createRelativePositionFromTypeIndex(yText, end); | ||
options.awareness.setLocalStateField(this._areaID, { | ||
user: options.awareness.clientID, | ||
selection: true, | ||
start: JSON.stringify(startRel), | ||
end: JSON.stringify(endRel), | ||
name: options.clientName, | ||
color: options.color || { r: 45, g: 80, b: 237 } | ||
}); | ||
}); | ||
textField.addEventListener("focusout", () => { | ||
options.awareness.setLocalStateField(this._areaID, { | ||
user: options.awareness.clientID, | ||
selection: false | ||
}); | ||
}); | ||
textField.addEventListener("scroll", () => { | ||
this.rePositionCursors(); | ||
}); | ||
} | ||
} | ||
rePositionCursors() { | ||
if (this._textField) { | ||
for (const [_index, cursor] of this._cursors) { | ||
cursor.rePosition(this._textField); | ||
} | ||
} | ||
} | ||
} | ||
Object.defineProperty(TextAreaCursors, "areaIDCounter", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
var DIFF_DELETE = -1; | ||
var DIFF_INSERT = 1; | ||
var DIFF_EQUAL = 0; | ||
function diff_main(text1, text2, cursor_pos, _fix_unicode) { | ||
if (text1 === text2) { | ||
if (text1) { | ||
return [[DIFF_EQUAL, text1]]; | ||
} | ||
return []; | ||
} | ||
if (cursor_pos != null) { | ||
var editdiff = find_cursor_edit_diff(text1, text2, cursor_pos); | ||
if (editdiff) { | ||
return editdiff; | ||
} | ||
} | ||
var commonlength = diff_commonPrefix(text1, text2); | ||
var commonprefix = text1.substring(0, commonlength); | ||
text1 = text1.substring(commonlength); | ||
text2 = text2.substring(commonlength); | ||
commonlength = diff_commonSuffix(text1, text2); | ||
var commonsuffix = text1.substring(text1.length - commonlength); | ||
text1 = text1.substring(0, text1.length - commonlength); | ||
text2 = text2.substring(0, text2.length - commonlength); | ||
var diffs = diff_compute_(text1, text2); | ||
if (commonprefix) { | ||
diffs.unshift([DIFF_EQUAL, commonprefix]); | ||
} | ||
if (commonsuffix) { | ||
diffs.push([DIFF_EQUAL, commonsuffix]); | ||
} | ||
diff_cleanupMerge(diffs, _fix_unicode); | ||
return diffs; | ||
} | ||
function diff_compute_(text1, text2) { | ||
var diffs; | ||
if (!text1) { | ||
return [[DIFF_INSERT, text2]]; | ||
} | ||
if (!text2) { | ||
return [[DIFF_DELETE, text1]]; | ||
} | ||
var longtext = text1.length > text2.length ? text1 : text2; | ||
var shorttext = text1.length > text2.length ? text2 : text1; | ||
var i = longtext.indexOf(shorttext); | ||
if (i !== -1) { | ||
diffs = [ | ||
[DIFF_INSERT, longtext.substring(0, i)], | ||
[DIFF_EQUAL, shorttext], | ||
[DIFF_INSERT, longtext.substring(i + shorttext.length)] | ||
]; | ||
if (text1.length > text2.length) { | ||
diffs[0][0] = diffs[2][0] = DIFF_DELETE; | ||
} | ||
return diffs; | ||
} | ||
if (shorttext.length === 1) { | ||
return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; | ||
} | ||
var hm = diff_halfMatch_(text1, text2); | ||
if (hm) { | ||
var text1_a = hm[0]; | ||
var text1_b = hm[1]; | ||
var text2_a = hm[2]; | ||
var text2_b = hm[3]; | ||
var mid_common = hm[4]; | ||
var diffs_a = diff_main(text1_a, text2_a); | ||
var diffs_b = diff_main(text1_b, text2_b); | ||
return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b); | ||
} | ||
return diff_bisect_(text1, text2); | ||
} | ||
function diff_bisect_(text1, text2) { | ||
var text1_length = text1.length; | ||
var text2_length = text2.length; | ||
var max_d = Math.ceil((text1_length + text2_length) / 2); | ||
var v_offset = max_d; | ||
var v_length = 2 * max_d; | ||
var v1 = new Array(v_length); | ||
var v2 = new Array(v_length); | ||
for (var x = 0; x < v_length; x++) { | ||
v1[x] = -1; | ||
v2[x] = -1; | ||
} | ||
v1[v_offset + 1] = 0; | ||
v2[v_offset + 1] = 0; | ||
var delta = text1_length - text2_length; | ||
var front = delta % 2 !== 0; | ||
var k1start = 0; | ||
var k1end = 0; | ||
var k2start = 0; | ||
var k2end = 0; | ||
for (var d = 0; d < max_d; d++) { | ||
for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { | ||
var k1_offset = v_offset + k1; | ||
var x1; | ||
if (k1 === -d || k1 !== d && v1[k1_offset - 1] < v1[k1_offset + 1]) { | ||
x1 = v1[k1_offset + 1]; | ||
} else { | ||
x1 = v1[k1_offset - 1] + 1; | ||
} | ||
var y1 = x1 - k1; | ||
while (x1 < text1_length && y1 < text2_length && text1.charAt(x1) === text2.charAt(y1)) { | ||
x1++; | ||
y1++; | ||
} | ||
v1[k1_offset] = x1; | ||
if (x1 > text1_length) { | ||
k1end += 2; | ||
} else if (y1 > text2_length) { | ||
k1start += 2; | ||
} else if (front) { | ||
var k2_offset = v_offset + delta - k1; | ||
if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] !== -1) { | ||
var x2 = text1_length - v2[k2_offset]; | ||
if (x1 >= x2) { | ||
return diff_bisectSplit_(text1, text2, x1, y1); | ||
} | ||
} | ||
} | ||
} | ||
for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { | ||
var k2_offset = v_offset + k2; | ||
var x2; | ||
if (k2 === -d || k2 !== d && v2[k2_offset - 1] < v2[k2_offset + 1]) { | ||
x2 = v2[k2_offset + 1]; | ||
} else { | ||
x2 = v2[k2_offset - 1] + 1; | ||
} | ||
var y2 = x2 - k2; | ||
while (x2 < text1_length && y2 < text2_length && text1.charAt(text1_length - x2 - 1) === text2.charAt(text2_length - y2 - 1)) { | ||
x2++; | ||
y2++; | ||
} | ||
v2[k2_offset] = x2; | ||
if (x2 > text1_length) { | ||
k2end += 2; | ||
} else if (y2 > text2_length) { | ||
k2start += 2; | ||
} else if (!front) { | ||
var k1_offset = v_offset + delta - k2; | ||
if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] !== -1) { | ||
var x1 = v1[k1_offset]; | ||
var y1 = v_offset + x1 - k1_offset; | ||
x2 = text1_length - x2; | ||
if (x1 >= x2) { | ||
return diff_bisectSplit_(text1, text2, x1, y1); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; | ||
} | ||
function diff_bisectSplit_(text1, text2, x, y) { | ||
var text1a = text1.substring(0, x); | ||
var text2a = text2.substring(0, y); | ||
var text1b = text1.substring(x); | ||
var text2b = text2.substring(y); | ||
var diffs = diff_main(text1a, text2a); | ||
var diffsb = diff_main(text1b, text2b); | ||
return diffs.concat(diffsb); | ||
} | ||
function diff_commonPrefix(text1, text2) { | ||
if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) { | ||
return 0; | ||
} | ||
var pointermin = 0; | ||
var pointermax = Math.min(text1.length, text2.length); | ||
var pointermid = pointermax; | ||
var pointerstart = 0; | ||
while (pointermin < pointermid) { | ||
if (text1.substring(pointerstart, pointermid) == text2.substring(pointerstart, pointermid)) { | ||
pointermin = pointermid; | ||
pointerstart = pointermin; | ||
} else { | ||
pointermax = pointermid; | ||
} | ||
pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); | ||
} | ||
if (is_surrogate_pair_start(text1.charCodeAt(pointermid - 1))) { | ||
pointermid--; | ||
} | ||
return pointermid; | ||
} | ||
function diff_commonSuffix(text1, text2) { | ||
if (!text1 || !text2 || text1.slice(-1) !== text2.slice(-1)) { | ||
return 0; | ||
} | ||
var pointermin = 0; | ||
var pointermax = Math.min(text1.length, text2.length); | ||
var pointermid = pointermax; | ||
var pointerend = 0; | ||
while (pointermin < pointermid) { | ||
if (text1.substring(text1.length - pointermid, text1.length - pointerend) == text2.substring(text2.length - pointermid, text2.length - pointerend)) { | ||
pointermin = pointermid; | ||
pointerend = pointermin; | ||
} else { | ||
pointermax = pointermid; | ||
} | ||
pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); | ||
} | ||
if (is_surrogate_pair_end(text1.charCodeAt(text1.length - pointermid))) { | ||
pointermid--; | ||
} | ||
return pointermid; | ||
} | ||
function diff_halfMatch_(text1, text2) { | ||
var longtext = text1.length > text2.length ? text1 : text2; | ||
var shorttext = text1.length > text2.length ? text2 : text1; | ||
if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { | ||
return null; | ||
} | ||
function diff_halfMatchI_(longtext2, shorttext2, i) { | ||
var seed = longtext2.substring(i, i + Math.floor(longtext2.length / 4)); | ||
var j = -1; | ||
var best_common = ""; | ||
var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b; | ||
while ((j = shorttext2.indexOf(seed, j + 1)) !== -1) { | ||
var prefixLength = diff_commonPrefix(longtext2.substring(i), shorttext2.substring(j)); | ||
var suffixLength = diff_commonSuffix(longtext2.substring(0, i), shorttext2.substring(0, j)); | ||
if (best_common.length < suffixLength + prefixLength) { | ||
best_common = shorttext2.substring(j - suffixLength, j) + shorttext2.substring(j, j + prefixLength); | ||
best_longtext_a = longtext2.substring(0, i - suffixLength); | ||
best_longtext_b = longtext2.substring(i + prefixLength); | ||
best_shorttext_a = shorttext2.substring(0, j - suffixLength); | ||
best_shorttext_b = shorttext2.substring(j + prefixLength); | ||
} | ||
} | ||
if (best_common.length * 2 >= longtext2.length) { | ||
return [ | ||
best_longtext_a, | ||
best_longtext_b, | ||
best_shorttext_a, | ||
best_shorttext_b, | ||
best_common | ||
]; | ||
} else { | ||
return null; | ||
} | ||
} | ||
var hm1 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 4)); | ||
var hm2 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 2)); | ||
var hm; | ||
if (!hm1 && !hm2) { | ||
return null; | ||
} else if (!hm2) { | ||
hm = hm1; | ||
} else if (!hm1) { | ||
hm = hm2; | ||
} else { | ||
hm = hm1[4].length > hm2[4].length ? hm1 : hm2; | ||
} | ||
var text1_a, text1_b, text2_a, text2_b; | ||
if (text1.length > text2.length) { | ||
text1_a = hm[0]; | ||
text1_b = hm[1]; | ||
text2_a = hm[2]; | ||
text2_b = hm[3]; | ||
} else { | ||
text2_a = hm[0]; | ||
text2_b = hm[1]; | ||
text1_a = hm[2]; | ||
text1_b = hm[3]; | ||
} | ||
var mid_common = hm[4]; | ||
return [text1_a, text1_b, text2_a, text2_b, mid_common]; | ||
} | ||
function diff_cleanupMerge(diffs, fix_unicode) { | ||
diffs.push([DIFF_EQUAL, ""]); | ||
var pointer = 0; | ||
var count_delete = 0; | ||
var count_insert = 0; | ||
var text_delete = ""; | ||
var text_insert = ""; | ||
var commonlength; | ||
while (pointer < diffs.length) { | ||
if (pointer < diffs.length - 1 && !diffs[pointer][1]) { | ||
diffs.splice(pointer, 1); | ||
continue; | ||
} | ||
switch (diffs[pointer][0]) { | ||
case DIFF_INSERT: | ||
count_insert++; | ||
text_insert += diffs[pointer][1]; | ||
pointer++; | ||
break; | ||
case DIFF_DELETE: | ||
count_delete++; | ||
text_delete += diffs[pointer][1]; | ||
pointer++; | ||
break; | ||
case DIFF_EQUAL: | ||
var previous_equality = pointer - count_insert - count_delete - 1; | ||
if (fix_unicode) { | ||
if (previous_equality >= 0 && ends_with_pair_start(diffs[previous_equality][1])) { | ||
var stray = diffs[previous_equality][1].slice(-1); | ||
diffs[previous_equality][1] = diffs[previous_equality][1].slice(0, -1); | ||
text_delete = stray + text_delete; | ||
text_insert = stray + text_insert; | ||
if (!diffs[previous_equality][1]) { | ||
diffs.splice(previous_equality, 1); | ||
pointer--; | ||
var k = previous_equality - 1; | ||
if (diffs[k] && diffs[k][0] === DIFF_INSERT) { | ||
count_insert++; | ||
text_insert = diffs[k][1] + text_insert; | ||
k--; | ||
} | ||
if (diffs[k] && diffs[k][0] === DIFF_DELETE) { | ||
count_delete++; | ||
text_delete = diffs[k][1] + text_delete; | ||
k--; | ||
} | ||
previous_equality = k; | ||
} | ||
} | ||
if (starts_with_pair_end(diffs[pointer][1])) { | ||
var stray = diffs[pointer][1].charAt(0); | ||
diffs[pointer][1] = diffs[pointer][1].slice(1); | ||
text_delete += stray; | ||
text_insert += stray; | ||
} | ||
} | ||
if (pointer < diffs.length - 1 && !diffs[pointer][1]) { | ||
diffs.splice(pointer, 1); | ||
break; | ||
} | ||
if (text_delete.length > 0 || text_insert.length > 0) { | ||
if (text_delete.length > 0 && text_insert.length > 0) { | ||
commonlength = diff_commonPrefix(text_insert, text_delete); | ||
if (commonlength !== 0) { | ||
if (previous_equality >= 0) { | ||
diffs[previous_equality][1] += text_insert.substring(0, commonlength); | ||
} else { | ||
diffs.splice(0, 0, [DIFF_EQUAL, text_insert.substring(0, commonlength)]); | ||
pointer++; | ||
} | ||
text_insert = text_insert.substring(commonlength); | ||
text_delete = text_delete.substring(commonlength); | ||
} | ||
commonlength = diff_commonSuffix(text_insert, text_delete); | ||
if (commonlength !== 0) { | ||
diffs[pointer][1] = text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1]; | ||
text_insert = text_insert.substring(0, text_insert.length - commonlength); | ||
text_delete = text_delete.substring(0, text_delete.length - commonlength); | ||
} | ||
} | ||
var n = count_insert + count_delete; | ||
if (text_delete.length === 0 && text_insert.length === 0) { | ||
diffs.splice(pointer - n, n); | ||
pointer = pointer - n; | ||
} else if (text_delete.length === 0) { | ||
diffs.splice(pointer - n, n, [DIFF_INSERT, text_insert]); | ||
pointer = pointer - n + 1; | ||
} else if (text_insert.length === 0) { | ||
diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete]); | ||
pointer = pointer - n + 1; | ||
} else { | ||
diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete], [DIFF_INSERT, text_insert]); | ||
pointer = pointer - n + 2; | ||
} | ||
} | ||
if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) { | ||
diffs[pointer - 1][1] += diffs[pointer][1]; | ||
diffs.splice(pointer, 1); | ||
} else { | ||
pointer++; | ||
} | ||
count_insert = 0; | ||
count_delete = 0; | ||
text_delete = ""; | ||
text_insert = ""; | ||
break; | ||
} | ||
} | ||
if (diffs[diffs.length - 1][1] === "") { | ||
diffs.pop(); | ||
} | ||
var changes = false; | ||
pointer = 1; | ||
while (pointer < diffs.length - 1) { | ||
if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) { | ||
if (diffs[pointer][1].substring(diffs[pointer][1].length - diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) { | ||
diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length); | ||
diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; | ||
diffs.splice(pointer - 1, 1); | ||
changes = true; | ||
} else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == diffs[pointer + 1][1]) { | ||
diffs[pointer - 1][1] += diffs[pointer + 1][1]; | ||
diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1]; | ||
diffs.splice(pointer + 1, 1); | ||
changes = true; | ||
} | ||
} | ||
pointer++; | ||
} | ||
if (changes) { | ||
diff_cleanupMerge(diffs, fix_unicode); | ||
} | ||
} | ||
function is_surrogate_pair_start(charCode) { | ||
return charCode >= 55296 && charCode <= 56319; | ||
} | ||
function is_surrogate_pair_end(charCode) { | ||
return charCode >= 56320 && charCode <= 57343; | ||
} | ||
function starts_with_pair_end(str) { | ||
return is_surrogate_pair_end(str.charCodeAt(0)); | ||
} | ||
function ends_with_pair_start(str) { | ||
return is_surrogate_pair_start(str.charCodeAt(str.length - 1)); | ||
} | ||
function remove_empty_tuples(tuples) { | ||
var ret = []; | ||
for (var i = 0; i < tuples.length; i++) { | ||
if (tuples[i][1].length > 0) { | ||
ret.push(tuples[i]); | ||
} | ||
} | ||
return ret; | ||
} | ||
function make_edit_splice(before, oldMiddle, newMiddle, after) { | ||
if (ends_with_pair_start(before) || starts_with_pair_end(after)) { | ||
return null; | ||
} | ||
return remove_empty_tuples([ | ||
[DIFF_EQUAL, before], | ||
[DIFF_DELETE, oldMiddle], | ||
[DIFF_INSERT, newMiddle], | ||
[DIFF_EQUAL, after] | ||
]); | ||
} | ||
function find_cursor_edit_diff(oldText, newText, cursor_pos) { | ||
var oldRange = typeof cursor_pos === "number" ? { index: cursor_pos, length: 0 } : cursor_pos.oldRange; | ||
var newRange = typeof cursor_pos === "number" ? null : cursor_pos.newRange; | ||
var oldLength = oldText.length; | ||
var newLength = newText.length; | ||
if (oldRange.length === 0 && (newRange === null || newRange.length === 0)) { | ||
var oldCursor = oldRange.index; | ||
var oldBefore = oldText.slice(0, oldCursor); | ||
var oldAfter = oldText.slice(oldCursor); | ||
var maybeNewCursor = newRange ? newRange.index : null; | ||
editBefore: { | ||
var newCursor = oldCursor + newLength - oldLength; | ||
if (maybeNewCursor !== null && maybeNewCursor !== newCursor) { | ||
break editBefore; | ||
} | ||
if (newCursor < 0 || newCursor > newLength) { | ||
break editBefore; | ||
} | ||
var newBefore = newText.slice(0, newCursor); | ||
var newAfter = newText.slice(newCursor); | ||
if (newAfter !== oldAfter) { | ||
break editBefore; | ||
} | ||
var prefixLength = Math.min(oldCursor, newCursor); | ||
var oldPrefix = oldBefore.slice(0, prefixLength); | ||
var newPrefix = newBefore.slice(0, prefixLength); | ||
if (oldPrefix !== newPrefix) { | ||
break editBefore; | ||
} | ||
var oldMiddle = oldBefore.slice(prefixLength); | ||
var newMiddle = newBefore.slice(prefixLength); | ||
return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldAfter); | ||
} | ||
editAfter: { | ||
if (maybeNewCursor !== null && maybeNewCursor !== oldCursor) { | ||
break editAfter; | ||
} | ||
var cursor = oldCursor; | ||
var newBefore = newText.slice(0, cursor); | ||
var newAfter = newText.slice(cursor); | ||
if (newBefore !== oldBefore) { | ||
break editAfter; | ||
} | ||
var suffixLength = Math.min(oldLength - cursor, newLength - cursor); | ||
var oldSuffix = oldAfter.slice(oldAfter.length - suffixLength); | ||
var newSuffix = newAfter.slice(newAfter.length - suffixLength); | ||
if (oldSuffix !== newSuffix) { | ||
break editAfter; | ||
} | ||
var oldMiddle = oldAfter.slice(0, oldAfter.length - suffixLength); | ||
var newMiddle = newAfter.slice(0, newAfter.length - suffixLength); | ||
return make_edit_splice(oldBefore, oldMiddle, newMiddle, oldSuffix); | ||
} | ||
} | ||
if (oldRange.length > 0 && newRange && newRange.length === 0) { | ||
replaceRange: { | ||
var oldPrefix = oldText.slice(0, oldRange.index); | ||
var oldSuffix = oldText.slice(oldRange.index + oldRange.length); | ||
var prefixLength = oldPrefix.length; | ||
var suffixLength = oldSuffix.length; | ||
if (newLength < prefixLength + suffixLength) { | ||
break replaceRange; | ||
} | ||
var newPrefix = newText.slice(0, prefixLength); | ||
var newSuffix = newText.slice(newLength - suffixLength); | ||
if (oldPrefix !== newPrefix || oldSuffix !== newSuffix) { | ||
break replaceRange; | ||
} | ||
var oldMiddle = oldText.slice(prefixLength, oldLength - suffixLength); | ||
var newMiddle = newText.slice(prefixLength, newLength - suffixLength); | ||
return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldSuffix); | ||
} | ||
} | ||
return null; | ||
} | ||
function diff(text1, text2, cursor_pos) { | ||
return diff_main(text1, text2, cursor_pos, true); | ||
} | ||
diff.INSERT = DIFF_INSERT; | ||
diff.DELETE = DIFF_DELETE; | ||
diff.EQUAL = DIFF_EQUAL; | ||
var diff_1 = diff; | ||
class TextAreaBinding { | ||
constructor(yText, textField) { | ||
constructor(yText, textField, options) { | ||
Object.defineProperty(this, "_cursors", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
let doc = yText.doc; | ||
@@ -12,6 +896,11 @@ if (doc === null) { | ||
} | ||
if (options) { | ||
this._cursors = new TextAreaCursors(yText, textField, options); | ||
} | ||
textField.value = yText.toString(); | ||
let relPosStart; | ||
let relPosEnd; | ||
let direction; | ||
doc.on("beforeTransaction", () => { | ||
direction = textField.selectionDirection; | ||
const r = this.createRange(textField); | ||
@@ -28,4 +917,5 @@ relPosStart = Y.createRelativePositionFromTypeIndex(yText, r.left); | ||
if (startPos !== null && endPos !== null) { | ||
textField.selectionStart = startPos.index; | ||
textField.selectionEnd = endPos.index; | ||
if (direction === null) | ||
direction = "forward"; | ||
textField.setSelectionRange(startPos.index, endPos.index, direction); | ||
} | ||
@@ -37,3 +927,3 @@ }); | ||
let content = textField.value; | ||
let diffs = diff(oldContent, content, r.left); | ||
let diffs = diff_1(oldContent, content, r.left); | ||
let pos = 0; | ||
@@ -58,3 +948,7 @@ for (let i = 0; i < diffs.length; i++) { | ||
} | ||
rePositionCursors() { | ||
var _a; | ||
(_a = this._cursors) == null ? void 0 : _a.rePositionCursors(); | ||
} | ||
} | ||
export { TextAreaBinding }; |
@@ -1,1 +0,1 @@ | ||
(function(o,s){typeof exports=="object"&&typeof module!="undefined"?s(exports,require("yjs"),require("fast-diff")):typeof define=="function"&&define.amd?define(["exports","yjs","fast-diff"],s):(o=typeof globalThis!="undefined"?globalThis:o||self,s(o["y-textArea"]={},o.Y,o.diff))})(this,function(o,s,_){"use strict";function h(n){return n&&typeof n=="object"&&"default"in n?n:{default:n}}function P(n){if(n&&n.__esModule)return n;var t={__proto__:null,[Symbol.toStringTag]:"Module"};return n&&Object.keys(n).forEach(function(e){if(e!=="default"){var r=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(t,e,r.get?r:{enumerable:!0,get:function(){return n[e]}})}}),t.default=n,Object.freeze(t)}var a=P(s),b=h(_);class m{constructor(t,e){let r=t.doc;if(r===null)throw new Error("Missing doc on yText");if(e.selectionStart===void 0||e.selectionEnd===void 0)throw new Error("textField argument doesn't look like a text field");e.value=t.toString();let p,v;r.on("beforeTransaction",()=>{const l=this.createRange(e);p=a.createRelativePositionFromTypeIndex(t,l.left),v=a.createRelativePositionFromTypeIndex(t,l.right)}),t.observe((l,d)=>{if(d.local)return;const c=a.createAbsolutePositionFromRelativePosition(p,r),f=a.createAbsolutePositionFromRelativePosition(v,r);e.value=t.toString(),c!==null&&f!==null&&(e.selectionStart=c.index,e.selectionEnd=f.index)}),e.addEventListener("input",()=>{const l=this.createRange(e);let d=t.toString(),c=e.value,f=b.default(d,c,l.left),u=0;for(let g=0;g<f.length;g++){let i=f[g];i[0]===0?u+=i[1].length:i[0]===-1?t.delete(u,i[1].length):(t.insert(u,i[1]),u+=i[1].length)}})}createRange(t){const e=t.selectionStart,r=t.selectionEnd;return{left:e,right:r}}}o.TextAreaBinding=m,Object.defineProperty(o,"__esModule",{value:!0}),o[Symbol.toStringTag]="Module"}); | ||
(function(R,M){typeof exports=="object"&&typeof module!="undefined"?M(exports,require("yjs")):typeof define=="function"&&define.amd?define(["exports","yjs"],M):(R=typeof globalThis!="undefined"?globalThis:R||self,M(R["y-textArea"]={},R.Y))})(this,function(R,M){"use strict";function Q(t){if(t&&t.__esModule)return t;var n={__proto__:null,[Symbol.toStringTag]:"Module"};return t&&Object.keys(t).forEach(function(e){if(e!=="default"){var i=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,i.get?i:{enumerable:!0,get:function(){return t[e]}})}}),n.default=t,Object.freeze(n)}var C=Q(M),N={exports:{}};(function(t){(function(){var n=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],e=typeof window!="undefined",i=e&&window.mozInnerScreenX!=null;function a(r,s,o){if(!e)throw new Error("textarea-caret-position#getCaretCoordinates should only be called in a browser");var l=o&&o.debug||!1;if(l){var c=document.querySelector("#input-textarea-caret-position-mirror-div");c&&c.parentNode.removeChild(c)}var h=document.createElement("div");h.id="input-textarea-caret-position-mirror-div",document.body.appendChild(h);var u=h.style,d=window.getComputedStyle?window.getComputedStyle(r):r.currentStyle,b=r.nodeName==="INPUT";u.whiteSpace="pre-wrap",b||(u.wordWrap="break-word"),u.position="absolute",l||(u.visibility="hidden"),n.forEach(function(v){b&&v==="lineHeight"?u.lineHeight=d.height:u[v]=d[v]}),i?r.scrollHeight>parseInt(d.height)&&(u.overflowY="scroll"):u.overflow="hidden",h.textContent=r.value.substring(0,s),b&&(h.textContent=h.textContent.replace(/\s/g,"\xA0"));var g=document.createElement("span");g.textContent=r.value.substring(s)||".",h.appendChild(g);var m={top:g.offsetTop+parseInt(d.borderTopWidth),left:g.offsetLeft+parseInt(d.borderLeftWidth),height:parseInt(d.lineHeight)};return l?g.style.backgroundColor="#aaa":document.body.removeChild(h),m}t.exports=a})()})(N);var T=N.exports;function V(t,n){const e=Math.max(t.x,n.x),i=Math.min(t.x+t.width,n.x+n.width);if(i<e)return null;const a=Math.max(t.y,n.y),r=Math.min(t.y+t.height,n.y+n.height);return r<a?null:new F(e,a,i-e,r-a)}class F{constructor(n,e,i,a){this.x=n,this.y=e,this.width=i,this.height=a}get area(){return this.width*this.height}}var G=V;const K=["keyup","mouseup","touchstart","paste","cut","selectend"];class Z{constructor(n,e,i){Object.defineProperty(this,"_div",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_nameDiv",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_color",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_fontSize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_selectedIndex",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._selectedIndex={start:-1,end:-1},this._fontSize=n,this._color=e,this._div=document.createElement("div"),this._div.style.position="absolute",this._div.style.backgroundColor=`rgba(${e.r}, ${e.g}, ${e.b}, 0.4)`,this._div.style.height=n,this._div.style.width="1px",this._div.style.display="none",this._div.classList.add("selectedText"),document.body.appendChild(this._div),i!==void 0&&(this._nameDiv=document.createElement("div"),this._nameDiv.style.position="absolute",this._nameDiv.style.display="none",this._nameDiv.style.backgroundColor=`rgba(${e.r}, ${e.g}, ${e.b}, 1.0)`,this._nameDiv.classList.add("nameTag"),this._nameDiv.innerHTML=i,document.body.appendChild(this._nameDiv))}show(){this._div.style.display="block",this._nameDiv&&(this._nameDiv.style.display="block")}hide(){this._div.style.display="none",this._nameDiv&&(this._nameDiv.style.display="none")}setPosition(n,e){this._selectedIndex={start:n,end:e}}setWidth(n){this._div.style.width=n+"px",n===1?this._div.style.backgroundColor=`rgba(${this._color.r}, ${this._color.g}, ${this._color.b}, 1.0)`:this._div.style.backgroundColor=`rgba(${this._color.r}, ${this._color.g}, ${this._color.b}, 0.4)`}rePosition(n){if(this._selectedIndex.start===-1||this._selectedIndex.end===-1)return;const e=T(n,this._selectedIndex.start),i=n.offsetTop-n.scrollTop+e.top,a=n.offsetLeft-n.scrollLeft+e.left;let r=1,s=0;if(this._selectedIndex.start!==this._selectedIndex.end){let h=T(n,this._selectedIndex.end);r=h.left-e.left,s=h.top-e.top,s!==0&&(r=1)}const o={x:n.offsetLeft,y:n.offsetTop,width:n.clientWidth,height:n.clientHeight},l={x:a,y:i,width:r,height:parseInt(this._fontSize)},c=G(o,l);if(!c){this.hide();return}this._div.style.top=c.y+"px",this._div.style.left=c.x+"px",this.setWidth(c.width),this.show(),this._nameDiv&&(this._nameDiv.style.top=c.y+parseInt(this._fontSize)+"px",this._nameDiv.style.left=c.x+"px")}destroy(){document.body.removeChild(this._div),this._nameDiv&&document.body.removeChild(this._nameDiv)}}class A{constructor(n,e,i){if(Object.defineProperty(this,"_cursors",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_areaID",{enumerable:!0,configurable:!0,writable:!0,value:""}),Object.defineProperty(this,"_textField",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._areaID=(A.areaIDCounter++).toString(),this._textField=e,e.selectionStart===null||e.selectionEnd===null)throw new Error("unSupported Input type");const a=n.doc;if(a===null)throw new Error("Missing doc on yText");i.awareness.on("update",r=>{if(r.removed.length!=0){for(const l of r.removed)if(this._cursors.has(l)){const c=this._cursors.get(l);c==null||c.destroy(),this._cursors.delete(l)}}const s=getComputedStyle(e).getPropertyValue("font-size"),o=i.awareness.getStates();for(const[l,c]of o.entries()){if(l===i.awareness.clientID)continue;const h=c[this._areaID];if(h===void 0)continue;const u=h.start,d=h.end,b=h.name,g=h.color,m=h.selection;this._cursors.has(l)||this._cursors.set(l,new Z(s,g,b));const v=this._cursors.get(l);if(!m){v==null||v.setPosition(-1,-1),v==null||v.hide();continue}if(u===void 0||d===void 0)continue;const f=C.createAbsolutePositionFromRelativePosition(JSON.parse(u),a),_=C.createAbsolutePositionFromRelativePosition(JSON.parse(d),a);if(f===null||_===null){v==null||v.hide();continue}v==null||v.setPosition(f.index,_.index),v==null||v.rePosition(e)}});for(const r of K)e.addEventListener(r,()=>{const s=e.selectionStart,o=e.selectionEnd,l=C.createRelativePositionFromTypeIndex(n,s),c=C.createRelativePositionFromTypeIndex(n,o);i.awareness.setLocalStateField(this._areaID,{user:i.awareness.clientID,selection:!0,start:JSON.stringify(l),end:JSON.stringify(c),name:i.clientName,color:i.color||{r:45,g:80,b:237}})}),e.addEventListener("focusout",()=>{i.awareness.setLocalStateField(this._areaID,{user:i.awareness.clientID,selection:!1})}),e.addEventListener("scroll",()=>{this.rePositionCursors()})}rePositionCursors(){if(this._textField)for(const[n,e]of this._cursors)e.rePosition(this._textField)}}Object.defineProperty(A,"areaIDCounter",{enumerable:!0,configurable:!0,writable:!0,value:0});var E=-1,D=1,P=0;function j(t,n,e,i){if(t===n)return t?[[P,t]]:[];if(e!=null){var a=te(t,n,e);if(a)return a}var r=L(t,n),s=t.substring(0,r);t=t.substring(r),n=n.substring(r),r=$(t,n);var o=t.substring(t.length-r);t=t.substring(0,t.length-r),n=n.substring(0,n.length-r);var l=k(t,n);return s&&l.unshift([P,s]),o&&l.push([P,o]),Y(l,i),l}function k(t,n){var e;if(!t)return[[D,n]];if(!n)return[[E,t]];var i=t.length>n.length?t:n,a=t.length>n.length?n:t,r=i.indexOf(a);if(r!==-1)return e=[[D,i.substring(0,r)],[P,a],[D,i.substring(r+a.length)]],t.length>n.length&&(e[0][0]=e[2][0]=E),e;if(a.length===1)return[[E,t],[D,n]];var s=x(t,n);if(s){var o=s[0],l=s[1],c=s[2],h=s[3],u=s[4],d=j(o,c),b=j(l,h);return d.concat([[P,u]],b)}return q(t,n)}function q(t,n){for(var e=t.length,i=n.length,a=Math.ceil((e+i)/2),r=a,s=2*a,o=new Array(s),l=new Array(s),c=0;c<s;c++)o[c]=-1,l[c]=-1;o[r+1]=0,l[r+1]=0;for(var h=e-i,u=h%2!==0,d=0,b=0,g=0,m=0,v=0;v<a;v++){for(var f=-v+d;f<=v-b;f+=2){var _=r+f,p;f===-v||f!==v&&o[_-1]<o[_+1]?p=o[_+1]:p=o[_-1]+1;for(var w=p-f;p<e&&w<i&&t.charAt(p)===n.charAt(w);)p++,w++;if(o[_]=p,p>e)b+=2;else if(w>i)d+=2;else if(u){var y=r+h-f;if(y>=0&&y<s&&l[y]!==-1){var S=e-l[y];if(p>=S)return H(t,n,p,w)}}}for(var I=-v+g;I<=v-m;I+=2){var y=r+I,S;I===-v||I!==v&&l[y-1]<l[y+1]?S=l[y+1]:S=l[y-1]+1;for(var O=S-I;S<e&&O<i&&t.charAt(e-S-1)===n.charAt(i-O-1);)S++,O++;if(l[y]=S,S>e)m+=2;else if(O>i)g+=2;else if(!u){var _=r+h-I;if(_>=0&&_<s&&o[_]!==-1){var p=o[_],w=r+p-_;if(S=e-S,p>=S)return H(t,n,p,w)}}}}return[[E,t],[D,n]]}function H(t,n,e,i){var a=t.substring(0,e),r=n.substring(0,i),s=t.substring(e),o=n.substring(i),l=j(a,r),c=j(s,o);return l.concat(c)}function L(t,n){if(!t||!n||t.charAt(0)!==n.charAt(0))return 0;for(var e=0,i=Math.min(t.length,n.length),a=i,r=0;e<a;)t.substring(r,a)==n.substring(r,a)?(e=a,r=e):i=a,a=Math.floor((i-e)/2+e);return J(t.charCodeAt(a-1))&&a--,a}function $(t,n){if(!t||!n||t.slice(-1)!==n.slice(-1))return 0;for(var e=0,i=Math.min(t.length,n.length),a=i,r=0;e<a;)t.substring(t.length-a,t.length-r)==n.substring(n.length-a,n.length-r)?(e=a,r=e):i=a,a=Math.floor((i-e)/2+e);return X(t.charCodeAt(t.length-a))&&a--,a}function x(t,n){var e=t.length>n.length?t:n,i=t.length>n.length?n:t;if(e.length<4||i.length*2<e.length)return null;function a(b,g,m){for(var v=b.substring(m,m+Math.floor(b.length/4)),f=-1,_="",p,w,y,S;(f=g.indexOf(v,f+1))!==-1;){var I=L(b.substring(m),g.substring(f)),O=$(b.substring(0,m),g.substring(0,f));_.length<O+I&&(_=g.substring(f-O,f)+g.substring(f,f+I),p=b.substring(0,m-O),w=b.substring(m+I),y=g.substring(0,f-O),S=g.substring(f+I))}return _.length*2>=b.length?[p,w,y,S,_]:null}var r=a(e,i,Math.ceil(e.length/4)),s=a(e,i,Math.ceil(e.length/2)),o;if(!r&&!s)return null;s?r?o=r[4].length>s[4].length?r:s:o=s:o=r;var l,c,h,u;t.length>n.length?(l=o[0],c=o[1],h=o[2],u=o[3]):(h=o[0],u=o[1],l=o[2],c=o[3]);var d=o[4];return[l,c,h,u,d]}function Y(t,n){t.push([P,""]);for(var e=0,i=0,a=0,r="",s="",o;e<t.length;){if(e<t.length-1&&!t[e][1]){t.splice(e,1);continue}switch(t[e][0]){case D:a++,s+=t[e][1],e++;break;case E:i++,r+=t[e][1],e++;break;case P:var l=e-a-i-1;if(n){if(l>=0&&U(t[l][1])){var c=t[l][1].slice(-1);if(t[l][1]=t[l][1].slice(0,-1),r=c+r,s=c+s,!t[l][1]){t.splice(l,1),e--;var h=l-1;t[h]&&t[h][0]===D&&(a++,s=t[h][1]+s,h--),t[h]&&t[h][0]===E&&(i++,r=t[h][1]+r,h--),l=h}}if(B(t[e][1])){var c=t[e][1].charAt(0);t[e][1]=t[e][1].slice(1),r+=c,s+=c}}if(e<t.length-1&&!t[e][1]){t.splice(e,1);break}if(r.length>0||s.length>0){r.length>0&&s.length>0&&(o=L(s,r),o!==0&&(l>=0?t[l][1]+=s.substring(0,o):(t.splice(0,0,[P,s.substring(0,o)]),e++),s=s.substring(o),r=r.substring(o)),o=$(s,r),o!==0&&(t[e][1]=s.substring(s.length-o)+t[e][1],s=s.substring(0,s.length-o),r=r.substring(0,r.length-o)));var u=a+i;r.length===0&&s.length===0?(t.splice(e-u,u),e=e-u):r.length===0?(t.splice(e-u,u,[D,s]),e=e-u+1):s.length===0?(t.splice(e-u,u,[E,r]),e=e-u+1):(t.splice(e-u,u,[E,r],[D,s]),e=e-u+2)}e!==0&&t[e-1][0]===P?(t[e-1][1]+=t[e][1],t.splice(e,1)):e++,a=0,i=0,r="",s="";break}}t[t.length-1][1]===""&&t.pop();var d=!1;for(e=1;e<t.length-1;)t[e-1][0]===P&&t[e+1][0]===P&&(t[e][1].substring(t[e][1].length-t[e-1][1].length)===t[e-1][1]?(t[e][1]=t[e-1][1]+t[e][1].substring(0,t[e][1].length-t[e-1][1].length),t[e+1][1]=t[e-1][1]+t[e+1][1],t.splice(e-1,1),d=!0):t[e][1].substring(0,t[e+1][1].length)==t[e+1][1]&&(t[e-1][1]+=t[e+1][1],t[e][1]=t[e][1].substring(t[e+1][1].length)+t[e+1][1],t.splice(e+1,1),d=!0)),e++;d&&Y(t,n)}function J(t){return t>=55296&&t<=56319}function X(t){return t>=56320&&t<=57343}function B(t){return X(t.charCodeAt(0))}function U(t){return J(t.charCodeAt(t.length-1))}function ee(t){for(var n=[],e=0;e<t.length;e++)t[e][1].length>0&&n.push(t[e]);return n}function W(t,n,e,i){return U(t)||B(i)?null:ee([[P,t],[E,n],[D,e],[P,i]])}function te(t,n,e){var i=typeof e=="number"?{index:e,length:0}:e.oldRange,a=typeof e=="number"?null:e.newRange,r=t.length,s=n.length;if(i.length===0&&(a===null||a.length===0)){var o=i.index,l=t.slice(0,o),c=t.slice(o),h=a?a.index:null;e:{var u=o+s-r;if(h!==null&&h!==u||u<0||u>s)break e;var d=n.slice(0,u),b=n.slice(u);if(b!==c)break e;var g=Math.min(o,u),m=l.slice(0,g),v=d.slice(0,g);if(m!==v)break e;var f=l.slice(g),_=d.slice(g);return W(m,f,_,c)}e:{if(h!==null&&h!==o)break e;var p=o,d=n.slice(0,p),b=n.slice(p);if(d!==l)break e;var w=Math.min(r-p,s-p),y=c.slice(c.length-w),S=b.slice(b.length-w);if(y!==S)break e;var f=c.slice(0,c.length-w),_=b.slice(0,b.length-w);return W(l,f,_,y)}}if(i.length>0&&a&&a.length===0){e:{var m=t.slice(0,i.index),y=t.slice(i.index+i.length),g=m.length,w=y.length;if(s<g+w)break e;var v=n.slice(0,g),S=n.slice(s-w);if(m!==v||y!==S)break e;var f=t.slice(g,r-w),_=n.slice(g,s-w);return W(m,f,_,y)}}return null}function z(t,n,e){return j(t,n,e,!0)}z.INSERT=D,z.DELETE=E,z.EQUAL=P;var ne=z;class re{constructor(n,e,i){Object.defineProperty(this,"_cursors",{enumerable:!0,configurable:!0,writable:!0,value:void 0});let a=n.doc;if(a===null)throw new Error("Missing doc on yText");if(e.selectionStart===void 0||e.selectionEnd===void 0)throw new Error("textField argument doesn't look like a text field");i&&(this._cursors=new A(n,e,i)),e.value=n.toString();let r,s,o;a.on("beforeTransaction",()=>{o=e.selectionDirection;const l=this.createRange(e);r=C.createRelativePositionFromTypeIndex(n,l.left),s=C.createRelativePositionFromTypeIndex(n,l.right)}),n.observe((l,c)=>{if(c.local)return;const h=C.createAbsolutePositionFromRelativePosition(r,a),u=C.createAbsolutePositionFromRelativePosition(s,a);e.value=n.toString(),h!==null&&u!==null&&(o===null&&(o="forward"),e.setSelectionRange(h.index,u.index,o))}),e.addEventListener("input",()=>{const l=this.createRange(e);let c=n.toString(),h=e.value,u=ne(c,h,l.left),d=0;for(let b=0;b<u.length;b++){let g=u[b];g[0]===0?d+=g[1].length:g[0]===-1?n.delete(d,g[1].length):(n.insert(d,g[1]),d+=g[1].length)}})}createRange(n){const e=n.selectionStart,i=n.selectionEnd;return{left:e,right:i}}rePositionCursors(){var n;(n=this._cursors)==null||n.rePositionCursors()}}R.TextAreaBinding=re,Object.defineProperty(R,"__esModule",{value:!0}),R[Symbol.toStringTag]="Module"}); |
@@ -15,5 +15,5 @@ { | ||
"types": "./dist/y-textArea.d.ts", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"scripts": { | ||
"dev": "vite", | ||
"dev": "vite --host", | ||
"build": "tsc && vite build", | ||
@@ -24,7 +24,12 @@ "preview": "vite preview", | ||
"devDependencies": { | ||
"@rollup/plugin-typescript": "^8.3.1", | ||
"@types/textarea-caret": "^3.0.1", | ||
"np": "^7.6.0", | ||
"tslib": "^2.3.1", | ||
"typescript": "^4.5.4", | ||
"vite": "^2.8.0", | ||
"y-websocket": "^1.3.18", | ||
"@rollup/plugin-typescript": "^8.3.1" | ||
"fast-diff": "^1.2.0", | ||
"rectangle-overlap": "^2.0.0", | ||
"textarea-caret": "^3.1.0" | ||
}, | ||
@@ -34,5 +39,2 @@ "peerDependencies": { | ||
}, | ||
"dependencies": { | ||
"fast-diff": "^1.2.0" | ||
}, | ||
"repository": { | ||
@@ -39,0 +41,0 @@ "type": "git", |
# y-TextArea | ||
This package binds a YJS, Y.Text type to a HTML input element where type="text" or a TextArea element. Shared cursors are not yet supported. | ||
This package binds a YJS, Y.Text type to a HTML input element where type="text" or a TextArea element. Shared cursors are also supported. | ||
## Example | ||
![](demo.gif) | ||
## Basic Example: | ||
```js | ||
@@ -18,2 +20,62 @@ import * as Y from 'yjs' | ||
## Shared Cursors | ||
Shared cursors are not natively supported by input elements or text area, so y-textarea uses an absolutely positioned div with alpha for the shared cursors. | ||
To enable shared cursors, supply at least the "awareness" parameter in the options. | ||
```typescript | ||
const wsProvider = new WebsocketProvider(`ws://someURL:1234`, 'roomname', doc) | ||
... | ||
const AreaBinding = new TextAreaBinding( | ||
yText, | ||
textArea, | ||
{ | ||
awareness : wsProvider.awareness, | ||
clientName: "SoftPenguin", | ||
color : {r:47, g:226, b:147} | ||
} | ||
); | ||
``` | ||
clientName and color can optionally be added. These control the shared cursor label and color. | ||
### Repositioning | ||
Due to how the shared cursors work its sometimes necessary to manually reposition the cursors, if for example your app, moves the text area, then the currently displayed cursors will have to be repositioned. To do this call `rePositionCursors()` | ||
``` typescript | ||
window.addEventListener('resize', ()=>{ | ||
AreaBinding.rePositionCursors(); | ||
}); | ||
``` | ||
### Styling cursors | ||
The selection box div can be styled using the "selectedText" class. The name tag can be styled using the "nameTag" class. e.g: | ||
```css | ||
.selectedText { | ||
border-radius: 2px; | ||
} | ||
.nameTag { | ||
color: white; | ||
font-family: Verdana, Geneva, sans-serif; | ||
font-weight: 400; | ||
font-style: italic; | ||
font-size: 12px; | ||
padding : 3px; | ||
border-radius: 3px; | ||
} | ||
``` | ||
There are some properties that y-textarea.js overwrites, so cant be styled using css, they are: | ||
- position | ||
- backgroundColor | ||
- height/width | ||
- display | ||
### Caveats | ||
Currently multi-line select on text areas doesn't work. It turns out that this was pretty tricky to implement performantly. I might think of a way to do this in the future. For now when multi-line selection is being done the cursor will stay at the start of the selection. | ||
## Run Demo | ||
@@ -20,0 +82,0 @@ Clone this repo, and run: |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
52221
1
8
1035
90
10
1
- Removedfast-diff@^1.2.0
- Removedfast-diff@1.3.0(transitive)