collaborative-ui
Version:
React component library for building real-time collaborative editing applications.
151 lines (150 loc) • 5.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CollaborativeFlexibleInput = void 0;
const tslib_1 = require("tslib");
const React = tslib_1.__importStar(require("react"));
const nano_theme_1 = require("nano-theme");
const util_1 = require("./util");
const collaborative_input_1 = require("collaborative-input");
const blockClass = (0, nano_theme_1.rule)({
d: 'inline-block',
pos: 'relative',
w: '100%',
});
const inputClass = (0, nano_theme_1.rule)({
d: 'inline-block',
va: 'bottom',
bxz: 'border-box',
ov: 'hidden',
pd: 0,
mr: 0,
bg: 0,
out: 0,
bd: 0,
col: 'inherit',
fw: 'inherit',
f: 'inherit',
lh: 'inherit',
ws: 'pre',
resize: 'none',
});
const sizerClass = (0, nano_theme_1.rule)({
d: 'inline-block',
pos: 'absolute',
// ov: 'hidden',
pe: 'none',
us: 'none',
bxz: 'border-box',
t: 0,
l: 0,
bd: 0,
ws: 'pre',
});
const CollaborativeFlexibleInput = ({ str, polling, inp, multiline, wrap, fullWidth, typebefore = '', typeahead = '', extraWidth, minWidth = 8, maxWidth, focus, onFocus, onBlur, onKeyDown, onSubmit, onCancel, onTab, }) => {
const inputRef = React.useRef(null);
const sizerRef = React.useRef(null);
const sizerValueRef = React.useRef(null);
const theme = (0, nano_theme_1.useTheme)();
// biome-ignore lint: manual dependency list
React.useLayoutEffect(() => {
if (!inputRef.current || !sizerRef.current)
return;
if (focus)
inputRef.current.focus();
(0, util_1.copyStyles)(inputRef.current, sizerRef.current, [
'font',
'fontSize',
'fontFamily',
'fontWeight',
'fontStyle',
'letterSpacing',
'textTransform',
'boxSizing',
]);
}, []);
// biome-ignore lint: manual dependency list
React.useLayoutEffect(() => {
const node = str();
if (!node)
return;
const sync = () => {
const sizerValue = sizerValueRef.current;
if (sizerValue)
sizerValue.textContent = node.view();
const input = inputRef.current;
const sizer = sizerRef.current;
if (!input || !sizer)
return;
let width = sizer.scrollWidth;
if (extraWidth)
width += extraWidth;
if (minWidth)
width = Math.max(width, minWidth);
if (maxWidth)
width = Math.min(width, maxWidth);
const style = input.style;
style.width = width + 'px';
if (multiline) {
const height = sizer.scrollHeight;
style.height = height + 'px';
}
};
return sync(), node.api.onChange.listen(sync);
}, [str]);
React.useEffect(() => {
const input = inputRef.current;
if (!input || !str)
return;
const unbind = (0, collaborative_input_1.bind)(str, input, !!polling);
return () => {
unbind();
};
}, [str, polling]);
const attr = {
ref: (input) => {
inputRef.current = input;
if (inp)
inp(input);
},
className: inputClass,
style: {
width: fullWidth ? '100%' : undefined,
whiteSpace: wrap ? 'pre-wrap' : 'pre',
display: fullWidth ? 'block' : 'inline-block',
},
onFocus,
onBlur,
onKeyDown: (e) => {
if (e.key === 'Enter' && (!multiline || e.ctrlKey)) {
if (onSubmit)
onSubmit(e);
}
else if (e.key === 'Escape') {
if (onCancel)
onCancel(e);
}
else if (e.key === 'Tab') {
if (onTab)
onTab(e);
}
if (onKeyDown)
onKeyDown(e);
},
};
const input = multiline ? React.createElement("textarea", { ...attr }) : React.createElement("input", { ...attr });
const style = {
display: fullWidth ? 'block' : 'inline-block',
width: fullWidth ? '100%' : undefined,
overflowX: fullWidth ? 'auto' : undefined,
whiteSpace: wrap ? 'pre-wrap' : 'pre',
};
return (React.createElement(React.Fragment, null,
!!typebefore && !fullWidth && React.createElement("span", { style: { color: theme.g(0.7), verticalAlign: 'top' } }, typebefore),
React.createElement("span", { className: blockClass, style: style },
input,
React.createElement("span", { ref: sizerRef, className: sizerClass, style: { width: fullWidth ? '100%' : undefined, whiteSpace: wrap ? 'pre-wrap' : 'pre' } },
React.createElement("span", { ref: sizerValueRef, style: { visibility: 'hidden' } }),
'\u200b',
!!typeahead && React.createElement("span", { style: { color: theme.g(0.7) } }, typeahead)))));
};
exports.CollaborativeFlexibleInput = CollaborativeFlexibleInput;