UNPKG

@carbon/react

Version:

React components for the Carbon Design System

195 lines (193 loc) 8.25 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const require_runtime = require("../../_virtual/_rolldown/runtime.js"); const require_usePrefix = require("../../internal/usePrefix.js"); const require_keys = require("../../internal/keyboard/keys.js"); const require_match = require("../../internal/keyboard/match.js"); const require_useId = require("../../internal/useId.js"); const require_noopFn = require("../../internal/noopFn.js"); const require_deprecate = require("../../prop-types/deprecate.js"); const require_useMergedRefs = require("../../internal/useMergedRefs.js"); const require_Tooltip = require("../Tooltip/Tooltip.js"); const require_events = require("../../tools/events.js"); const require_FormContext = require("../FluidForm/FormContext.js"); const require_utils = require("./utils.js"); let classnames = require("classnames"); classnames = require_runtime.__toESM(classnames); let react = require("react"); react = require_runtime.__toESM(react); let prop_types = require("prop-types"); prop_types = require_runtime.__toESM(prop_types); let react_jsx_runtime = require("react/jsx-runtime"); let _carbon_icons_react = require("@carbon/icons-react"); //#region src/components/Search/Search.tsx /** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const Search = react.default.forwardRef(({ autoComplete = "off", className, closeButtonLabelText = "Clear search input", defaultValue, disabled, isExpanded = true, id, labelText, light, onChange = () => {}, onClear = () => {}, onKeyDown, onExpand, placeholder = "Search", renderIcon, role, size = "md", type = "search", value, ...rest }, forwardRef) => { const hasPropValue = require_utils.isSearchValuePresent(value) || require_utils.isSearchValuePresent(defaultValue); const prefix = require_usePrefix.usePrefix(); const { isFluid } = (0, react.useContext)(require_FormContext.FormContext); const inputRef = (0, react.useRef)(null); const ref = require_useMergedRefs.useMergedRefs([forwardRef, inputRef]); const expandButtonRef = (0, react.useRef)(null); const inputId = require_useId.useId("search-input"); const uniqueId = id || inputId; const searchId = `${uniqueId}-search`; const [hasContent, setHasContent] = (0, react.useState)(hasPropValue || false); const searchClasses = (0, classnames.default)({ [`${prefix}--search`]: true, [`${prefix}--search--sm`]: size === "sm", [`${prefix}--search--md`]: size === "md", [`${prefix}--search--lg`]: size === "lg", [`${prefix}--search--light`]: light, [`${prefix}--search--disabled`]: disabled, [`${prefix}--search--fluid`]: isFluid }, className); const clearClasses = (0, classnames.default)({ [`${prefix}--search-close`]: true, [`${prefix}--search-close--hidden`]: !hasContent || !isExpanded }); (0, react.useEffect)(() => { if (typeof value !== "undefined") setHasContent(require_utils.isSearchValuePresent(value)); }, [value]); function clearInput() { if (!value && inputRef.current) inputRef.current.value = ""; if (inputRef.current) { const inputTarget = Object.assign({}, inputRef.current, { value: "" }); onChange({ bubbles: false, cancelable: false, currentTarget: inputRef.current, defaultPrevented: false, eventPhase: 0, isDefaultPrevented: () => false, isPropagationStopped: () => false, isTrusted: false, nativeEvent: new Event("change"), persist: require_noopFn.noopFn, preventDefault: require_noopFn.noopFn, stopPropagation: require_noopFn.noopFn, target: inputTarget, timeStamp: 0, type: "change" }); } onClear(); setHasContent(false); inputRef.current?.focus(); } function handleChange(event) { setHasContent(event.target.value !== ""); } function handleKeyDown(event) { if (require_match.match(event, require_keys.Escape)) { event.stopPropagation(); if (inputRef.current?.value) clearInput(); else if (onExpand && isExpanded) expandButtonRef.current?.focus(); } } function handleExpandButtonKeyDown(event) { if (require_match.match(event, require_keys.Enter) || require_match.match(event, require_keys.Space)) { event.stopPropagation(); if (onExpand) onExpand(event); } } const magnifierButton = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { "aria-labelledby": onExpand ? searchId : void 0, role: onExpand ? "button" : void 0, className: `${prefix}--search-magnifier`, onClick: onExpand, onKeyDown: handleExpandButtonKeyDown, tabIndex: onExpand && !isExpanded ? 0 : -1, ref: expandButtonRef, "aria-expanded": onExpand && isExpanded ? true : onExpand && !isExpanded ? false : void 0, "aria-controls": onExpand ? uniqueId : void 0, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CustomSearchIcon, { icon: renderIcon }) }); return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { role: "search", "aria-label": placeholder, className: searchClasses, children: [ onExpand && !isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tooltip.Tooltip, { className: `${prefix}--search-tooltip ${prefix}--search-magnifier-tooltip ${prefix}--icon-tooltip`, align: "top", label: "Search", children: magnifierButton }) : magnifierButton, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { id: searchId, htmlFor: uniqueId, className: `${prefix}--label`, children: labelText }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", { autoComplete, className: `${prefix}--search-input`, defaultValue, disabled, role, ref, id: uniqueId, onChange: require_events.composeEventHandlers([onChange, handleChange]), onKeyDown: require_events.composeEventHandlers([onKeyDown, handleKeyDown]), placeholder, type, value, tabIndex: onExpand && !isExpanded ? -1 : void 0, ...rest }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", { "aria-label": closeButtonLabelText, className: clearClasses, disabled, onClick: clearInput, title: closeButtonLabelText, type: "button", children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_carbon_icons_react.Close, {}) }) ] }); }); Search.displayName = "Search"; Search.propTypes = { autoComplete: prop_types.default.string, className: prop_types.default.string, closeButtonLabelText: prop_types.default.string, defaultValue: prop_types.default.oneOfType([prop_types.default.string, prop_types.default.number]), disabled: prop_types.default.bool, id: prop_types.default.string, isExpanded: prop_types.default.bool, labelText: prop_types.default.node.isRequired, light: require_deprecate.deprecate(prop_types.default.bool, "The `light` prop for `Search` is no longer needed and has been deprecated in v11 in favor of the new `Layer` component. It will be moved in the next major release."), onChange: prop_types.default.func, onClear: prop_types.default.func, onExpand: prop_types.default.func, onKeyDown: prop_types.default.func, placeholder: prop_types.default.string, renderIcon: prop_types.default.oneOfType([prop_types.default.func, prop_types.default.object]), role: require_deprecate.deprecate(prop_types.default.string, "The `role` prop has been deprecated since <input type=\"search\"> already provides correct semantics. It will be removed in the next major release of Carbon."), size: prop_types.default.oneOf([ "sm", "md", "lg" ]), type: prop_types.default.string, value: prop_types.default.oneOfType([prop_types.default.string, prop_types.default.number]) }; function CustomSearchIcon({ icon: Icon }) { const prefix = require_usePrefix.usePrefix(); if (Icon) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: `${prefix}--search-magnifier-icon` }); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_carbon_icons_react.Search, { className: `${prefix}--search-magnifier-icon` }); } CustomSearchIcon.propTypes = { icon: prop_types.default.oneOfType([prop_types.default.func, prop_types.default.object]) }; //#endregion exports.default = Search;