one
Version:
One is a React framework for web, iOS, and Android apps.
196 lines (195 loc) • 6.81 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var TextInput_exports = {};
__export(TextInput_exports, { TextInput: () => TextInput });
module.exports = __toCommonJS(TextInput_exports);
var import_react = require("react");
var import_syncNativeState = require("../../syncNativeState.cjs");
var import_DomView = require("../../web/DomView.cjs");
var import_textInputShared = require("./textInputShared.cjs");
var import_jsx_runtime = require("react/jsx-runtime");
const RESET = {
appearance: "none",
backgroundColor: "transparent",
borderStyle: "solid",
borderWidth: 0,
borderColor: "black",
borderRadius: 0,
boxSizing: "border-box",
font: "14px system-ui, -apple-system, sans-serif",
margin: 0,
padding: 0,
resize: "none"
};
const DEFAULT = {
padding: 8,
borderWidth: 1,
borderColor: "#d1d5db",
borderRadius: 6
};
const PSEUDO_RULES = `[data-one-text-input]::placeholder{color:var(--one-placeholder)}[data-one-text-input]::selection{background-color:var(--one-selection)}`;
function keyboardTypeToInputMode(keyboardType) {
switch (keyboardType) {
case "email-address": return "email";
case "number-pad":
case "numeric": return "numeric";
case "decimal-pad": return "decimal";
case "phone-pad": return "tel";
case "web-search": return "search";
case "url": return "url";
default: return void 0;
}
}
function returnKeyTypeToEnterKeyHint(returnKeyType) {
switch (returnKeyType) {
case "done":
case "go":
case "next":
case "previous":
case "search":
case "send": return returnKeyType;
default: return void 0;
}
}
function TextInput({ ref, value, onChangeText, placeholder, placeholderTextColor, autoFocus, editable: editableProp, readOnly, multiline, keyboardType, autoCapitalize, autoCorrect = true, autoComplete, returnKeyType, inputMode, enterKeyHint, onSubmitEditing, onFocus, onBlur, onContentSizeChange, onSelectionChange, selection, selectTextOnFocus, defaultValue, numberOfLines: numberOfLinesProp, rows, testID, nativeID, accessibilityLabel, style, textStyle, secureTextEntry, maxLength, caretHidden, selectionColor, cursorColor, textAlign }) {
const editable = (0, import_textInputShared.resolveEditable)(editableProp, readOnly);
const [focused, setFocused] = (0, import_react.useState)(false);
const initialFallbackRef = (0, import_react.useRef)(defaultValue ?? "");
const fallback = (0, import_syncNativeState.useNativeState)(initialFallbackRef.current);
const state = value ?? fallback;
const innerRef = (0, import_react.useRef)(null);
(0, import_react.useImperativeHandle)(ref, () => ({
focus: () => {
innerRef.current?.focus();
},
blur: () => {
innerRef.current?.blur();
},
clear: () => {
state.set("");
},
isFocused: () => innerRef.current != null && document.activeElement === innerRef.current,
setSelection: (start, end) => {
if (selection) selection.set({
start,
end
});
else innerRef.current?.setSelectionRange(start, end ?? start);
return Promise.resolve();
}
}), [state, selection]);
const selectionValue = selection?.value;
(0, import_react.useLayoutEffect)(() => {
const node = innerRef.current;
if (!node || !selectionValue) return;
node.setSelectionRange(selectionValue.start, selectionValue.end ?? selectionValue.start);
}, [selectionValue?.start, selectionValue?.end]);
const contentSize = (0, import_react.useRef)({
width: 0,
height: 0
});
(0, import_react.useLayoutEffect)(() => {
const node = innerRef.current;
if (!node || !onContentSizeChange) return;
const width = node.scrollWidth;
const height = node.scrollHeight;
if (width === contentSize.current.width && height === contentSize.current.height) return;
contentSize.current = {
width,
height
};
onContentSizeChange({
width,
height
});
}, [state.value, onContentSizeChange]);
const caretColor = caretHidden ? "transparent" : cursorColor ?? selectionColor;
const fieldStyle = {
...RESET,
...DEFAULT,
...focused && { borderColor: "#3b82f6" },
...multiline && { minHeight: 80 },
...(0, import_DomView.domStyle)(style),
...(0, import_DomView.domStyle)(textStyle),
...textAlign && textAlign !== "auto" && { textAlign },
...caretColor != null && { caretColor: String(caretColor) },
["--one-placeholder"]: String(placeholderTextColor ?? "#6b7280"),
...selectionColor != null && { ["--one-selection"]: String(selectionColor) }
};
const shared = {
ref: innerRef,
"data-one-text-input": "",
"data-testid": testID,
id: nativeID,
"aria-label": accessibilityLabel,
value: state.value,
placeholder,
autoFocus,
readOnly: !editable,
maxLength,
inputMode: inputMode ?? keyboardTypeToInputMode(keyboardType),
enterKeyHint: enterKeyHint ?? returnKeyTypeToEnterKeyHint(returnKeyType),
autoCapitalize,
autoCorrect: autoCorrect ? "on" : "off",
spellCheck: autoCorrect,
autoComplete,
style: fieldStyle,
onChange: (event) => {
const text = event.currentTarget.value;
state.set(text);
onChangeText?.(text);
},
onFocus: () => {
setFocused(true);
if (selectTextOnFocus) innerRef.current?.select();
onFocus?.();
},
onBlur: () => {
setFocused(false);
onBlur?.();
},
onSelect: (event) => {
if (!onSelectionChange && !selection) return;
const next = {
start: event.currentTarget.selectionStart ?? 0,
end: event.currentTarget.selectionEnd ?? 0
};
selection?.set(next);
onSelectionChange?.(next);
}
};
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", {
href: "one-text-input",
precedence: "default",
children: PSEUDO_RULES
}), multiline ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
...shared,
rows: numberOfLinesProp ?? rows
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
...shared,
type: secureTextEntry ? "password" : "text",
onKeyDown: (event) => {
if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
onSubmitEditing?.(event.currentTarget.value);
event.currentTarget.blur();
}
})] });
}