UNPKG

@helpwave/hightide

Version:

helpwave's component and theming library

334 lines (327 loc) 10.7 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/components/user-action/Input.tsx var Input_exports = {}; __export(Input_exports, { FormInput: () => FormInput, Input: () => Input, InputUncontrolled: () => InputUncontrolled }); module.exports = __toCommonJS(Input_exports); var import_react4 = require("react"); var import_clsx2 = __toESM(require("clsx")); // src/hooks/useDelay.ts var import_react = require("react"); var defaultOptions = { delay: 3e3, disabled: false }; function useDelay(options) { const [timer, setTimer] = (0, import_react.useState)(void 0); const { delay, disabled } = { ...defaultOptions, ...options }; const clearTimer = () => { clearTimeout(timer); setTimer(void 0); }; const restartTimer = (onDelayFinish) => { if (disabled) { return; } clearTimeout(timer); setTimer(setTimeout(() => { onDelayFinish(); setTimer(void 0); }, delay)); }; (0, import_react.useEffect)(() => { return () => { clearTimeout(timer); }; }, [timer]); (0, import_react.useEffect)(() => { if (disabled) { clearTimeout(timer); setTimer(void 0); } }, [disabled, timer]); return { restartTimer, clearTimer, hasActiveTimer: !!timer }; } // src/util/noop.ts var noop = () => void 0; // src/components/user-action/Label.tsx var import_clsx = __toESM(require("clsx")); var import_jsx_runtime = require("react/jsx-runtime"); var styleMapping = { labelSmall: "textstyle-label-sm", labelMedium: "textstyle-label-md", labelBig: "textstyle-label-lg" }; var Label = ({ children, name, labelType = "labelSmall", className, ...props }) => { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { ...props, className: (0, import_clsx.default)(styleMapping[labelType], className), children: children ? children : name }); }; // src/hooks/useFocusManagement.ts var import_react2 = require("react"); function useFocusManagement() { const getFocusableElements = (0, import_react2.useCallback)(() => { return Array.from( document.querySelectorAll( 'input, button, select, textarea, a[href], [tabindex]:not([tabindex="-1"])' ) ).filter( (el) => el instanceof HTMLElement && !el.hasAttribute("disabled") && !el.hasAttribute("hidden") && el.tabIndex !== -1 ); }, []); const getNextFocusElement = (0, import_react2.useCallback)(() => { const elements = getFocusableElements(); if (elements.length === 0) { return void 0; } let nextElement = elements[0]; if (document.activeElement instanceof HTMLElement) { const currentIndex = elements.indexOf(document.activeElement); nextElement = elements[(currentIndex + 1) % elements.length]; } return nextElement; }, [getFocusableElements]); const focusNext = (0, import_react2.useCallback)(() => { const nextElement = getNextFocusElement(); nextElement?.focus(); }, [getNextFocusElement]); const getPreviousFocusElement = (0, import_react2.useCallback)(() => { const elements = getFocusableElements(); if (elements.length === 0) { return void 0; } let previousElement = elements[0]; if (document.activeElement instanceof HTMLElement) { const currentIndex = elements.indexOf(document.activeElement); if (currentIndex === 0) { previousElement = elements[elements.length - 1]; } else { previousElement = elements[currentIndex - 1]; } } return previousElement; }, [getFocusableElements]); const focusPrevious = (0, import_react2.useCallback)(() => { const previousElement = getPreviousFocusElement(); if (previousElement) previousElement.focus(); }, [getPreviousFocusElement]); return { getFocusableElements, getNextFocusElement, getPreviousFocusElement, focusNext, focusPrevious }; } // src/hooks/useFocusOnceVisible.ts var import_react3 = __toESM(require("react")); var useFocusOnceVisible = (ref, disable = false) => { const [hasUsedFocus, setHasUsedFocus] = import_react3.default.useState(false); (0, import_react3.useEffect)(() => { if (disable || hasUsedFocus) { return; } const observer = new IntersectionObserver(([entry]) => { if (entry.isIntersecting && !hasUsedFocus) { ref.current?.focus(); setHasUsedFocus(hasUsedFocus); } }, { threshold: 0.1 }); if (ref.current) { observer.observe(ref.current); } return () => observer.disconnect(); }, [disable, hasUsedFocus, ref]); }; // src/components/user-action/Input.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); var getInputClassName = ({ disabled = false, hasError = false }) => { return (0, import_clsx2.default)( "px-2 py-1.5 rounded-md border-2", { "bg-input-background text-input-text hover:border-primary focus:border-primary": !disabled && !hasError, "bg-on-negative text-negative border-negative-border hover:border-negative-border-hover": !disabled && hasError, "bg-disabled-background text-disabled-text border-disabled-border": disabled } ); }; var defaultEditCompleteOptions = { onBlur: true, afterDelay: true, delay: 2500 }; var Input = (0, import_react4.forwardRef)(function Input2({ id, type = "text", value, label, onChange = noop, onChangeText = noop, onEditCompleted, className = "", allowEnterComplete = true, expanded = true, autoFocus = false, onBlur, editCompleteOptions, containerClassName, disabled, ...restProps }, forwardedRef) { const { onBlur: allowEditCompleteOnBlur, afterDelay, delay } = { ...defaultEditCompleteOptions, ...editCompleteOptions }; const { restartTimer, clearTimer } = useDelay({ delay, disabled: !afterDelay }); const innerRef = (0, import_react4.useRef)(null); const { focusNext } = useFocusManagement(); useFocusOnceVisible(innerRef, !autoFocus); (0, import_react4.useImperativeHandle)(forwardedRef, () => innerRef.current); const handleKeyDown = (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); innerRef.current?.blur(); focusNext(); } }; return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: (0, import_clsx2.default)({ "w-full": expanded }, containerClassName), children: [ label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Label, { ...label, htmlFor: id, className: (0, import_clsx2.default)("mb-1", label.className) }), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "input", { ...restProps, ref: innerRef, value, id, type, disabled, className: (0, import_clsx2.default)(getInputClassName({ disabled }), className), onKeyDown: allowEnterComplete ? handleKeyDown : void 0, onBlur: (event) => { onBlur?.(event); if (onEditCompleted && allowEditCompleteOnBlur) { onEditCompleted(event.target.value); clearTimer(); } }, onChange: (e) => { const value2 = e.target.value; if (onEditCompleted) { restartTimer(() => { if (innerRef.current) { innerRef.current.blur(); if (!allowEditCompleteOnBlur) { onEditCompleted(value2); } } else { onEditCompleted(value2); } }); } onChange(e); onChangeText(value2); } } ) ] }); }); var InputUncontrolled = ({ value = "", onChangeText = noop, ...props }) => { const [usedValue, setUsedValue] = (0, import_react4.useState)(value); (0, import_react4.useEffect)(() => { setUsedValue(value); }, [value]); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( Input, { ...props, value: usedValue, onChangeText: (text) => { setUsedValue(text); onChangeText(text); } } ); }; var FormInput = (0, import_react4.forwardRef)(function FormInput2({ id, labelText, errorText, className, labelClassName, errorClassName, containerClassName, required, disabled, ...restProps }, ref) { const input = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "input", { ...restProps, ref, id, disabled, className: (0, import_clsx2.default)( getInputClassName({ disabled, hasError: !!errorText }), className ) } ); return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: (0, import_clsx2.default)("flex flex-col gap-y-1", containerClassName), children: [ labelText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { htmlFor: id, className: (0, import_clsx2.default)("textstyle-label-md", labelClassName), children: [ labelText, required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-primary font-bold", children: "*" }) ] }), input, errorText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: id, className: (0, import_clsx2.default)("text-negative", errorClassName), children: errorText }) ] }); }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { FormInput, Input, InputUncontrolled }); //# sourceMappingURL=Input.js.map