UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

196 lines (195 loc) • 6.81 kB
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(); } })] }); }