UNPKG

@workday/canvas-kit-labs-react

Version:

Canvas Kit Labs is an incubator for new and experimental components. Since we have a rather rigorous process for getting components in at a production level, it can be valuable to make them available earlier while we continuously iterate on the API/functi

300 lines (299 loc) • 13 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SearchForm = void 0; const React = __importStar(require("react")); const tokens_1 = require("@workday/canvas-kit-react/tokens"); const common_1 = require("@workday/canvas-kit-react/common"); const button_1 = require("@workday/canvas-kit-react/button"); const canvas_system_icons_web_1 = require("@workday/canvas-system-icons-web"); const form_field_1 = require("@workday/canvas-kit-react/form-field"); const combobox_1 = require("@workday/canvas-kit-labs-react/combobox"); const text_input_1 = require("@workday/canvas-kit-react/text-input"); const themes_1 = require("./themes"); const chroma_js_1 = __importDefault(require("chroma-js")); function getInputColors(theme, isFocused) { return { background: isFocused && theme.backgroundFocus ? theme.backgroundFocus : theme.background, backgroundHover: theme.backgroundHover, color: isFocused && theme.colorFocus ? theme.colorFocus : theme.color, placeholderColor: isFocused && theme.placeholderColorFocus ? theme.placeholderColorFocus : theme.placeholderColor, boxShadow: isFocused && theme.boxShadowFocus ? theme.boxShadowFocus : theme.boxShadow, }; } const formCollapsedBackground = tokens_1.colors.frenchVanilla100; const maxWidth = 480; const minWidth = 120; const StyledSearchForm = (0, common_1.styled)('form')({ position: 'relative', flexGrow: 1, display: 'flex', alignItems: 'center', marginLeft: tokens_1.space.m, minWidth: minWidth, }, ({ isCollapsed, showForm, rightAlign, grow }) => { const collapseStyles = isCollapsed ? { top: 0, right: 0, left: 0, bottom: 0, margin: 0, position: showForm ? 'absolute' : 'relative', backgroundColor: showForm ? formCollapsedBackground : 'rgba(0, 0, 0, 0)', transition: 'background-color 120ms', maxWidth: showForm ? 'none' : `calc(${tokens_1.space.xl} + ${tokens_1.space.xxs})`, minWidth: `calc(${tokens_1.space.xl} + ${tokens_1.space.xs})`, overflow: showForm ? 'visible' : 'hidden', zIndex: 1, } : {}; const rightAlignStyles = rightAlign ? { textAlign: 'right', maxWidth: grow ? '100%' : maxWidth, } : {}; return { ...rightAlignStyles, ...collapseStyles }; }); const SearchContainer = (0, common_1.styled)('div')({ position: `relative`, display: 'flex', alignItems: 'center', width: `100%`, textAlign: 'left', }, ({ height }) => ({ minHeight: height, })); const SearchCombobox = (0, common_1.styled)(combobox_1.Combobox)({ width: `100%`, }); const SearchIcon = (0, common_1.styled)(button_1.TertiaryButton, { shouldForwardProp: (0, common_1.filterOutProps)(['isHidden', 'isCollapsed']), })(({ isCollapsed, isHidden }) => { return { position: `absolute`, margin: isCollapsed ? `auto ${tokens_1.space.xxs}` : `auto ${tokens_1.space.xxxs}`, top: 0, bottom: 0, left: 0, padding: 0, zIndex: 3, display: isHidden ? 'none' : 'flex', }; }); const CloseButton = (0, common_1.styled)(button_1.TertiaryButton, { shouldForwardProp: (0, common_1.filterOutProps)(['isCollapsed', 'showForm']), })(({ isCollapsed, showForm }) => { const collapseStyles = isCollapsed && showForm ? { display: 'inline-block', } : { display: 'none', }; return { position: `absolute`, top: 0, bottom: 0, right: 0, margin: `auto ${tokens_1.space.xxs}`, zIndex: 3, ...collapseStyles, }; }); const SearchField = (0, common_1.styled)(form_field_1.FormField)(({ isCollapsed, showForm, grow, height }) => { return { display: (isCollapsed && showForm) || !isCollapsed ? 'inline-block' : 'none', width: '100%', height: height, maxWidth: isCollapsed || grow ? '100%' : maxWidth, marginBottom: tokens_1.space.zero, '> div': { display: 'block', }, }; }); const SearchInput = (0, common_1.styled)(text_input_1.TextInput)(({ isCollapsed, inputColors, grow, height }) => { const collapseStyles = isCollapsed ? { fontSize: '20px', paddingLeft: `calc(${tokens_1.space.xl} + ${tokens_1.space.s})`, paddingRight: `calc(${tokens_1.space.xl} + ${tokens_1.space.s})`, maxWidth: 'none', minWidth: 0, backgroundColor: `rgba(0, 0, 0, 0)`, height: height, } : { maxWidth: grow ? '100%' : maxWidth, minWidth: minWidth, paddingLeft: `calc(${tokens_1.space.xl} + ${tokens_1.space.xxs})`, paddingRight: tokens_1.space.xl, backgroundColor: inputColors.background, height: height, }; return { fontSize: '14px', boxShadow: inputColors.boxShadow, color: inputColors.color, border: 'none', WebkitAppearance: 'none', transition: 'background-color 120ms, color 120ms, box-shadow 200ms, border-color 200ms', zIndex: 2, width: '100%', '&::-webkit-search-cancel-button': { display: 'none', }, '&::placeholder': { color: inputColors.placeholderColor, }, '&:placeholder-shown': { textOverflow: 'ellipsis', }, '&:not([disabled])': { '&:focus, &:active': { outline: 'none', boxShadow: inputColors.boxShadow, }, '&:hover': { backgroundColor: inputColors.backgroundHover, }, }, ...collapseStyles, }; }); class SearchForm extends React.Component { constructor() { super(...arguments); this.inputRef = React.createRef(); this.openRef = React.createRef(); this.defaultLabelId = (0, common_1.generateUniqueId)(); this.state = { showForm: false, searchQuery: '', isFocused: false, }; this.getTheme = () => { let theme; if (typeof this.props.searchTheme === 'number') { theme = themes_1.searchThemes[this.props.searchTheme]; } else if (this.props.searchTheme) { theme = this.props.searchTheme; } else { theme = themes_1.searchThemes[themes_1.SearchTheme.Light]; } return theme; }; this.getThemeColors = () => { const theme = this.props.isCollapsed && this.state.showForm ? themes_1.searchThemes[themes_1.SearchTheme.Transparent] : this.getTheme(); return getInputColors(theme, this.state.isFocused); }; this.getIconButtonType = () => { let background = this.getThemeColors().background || `#fff`; if (this.props.isCollapsed && this.state.showForm) { background = formCollapsedBackground; } const isDarkBackground = (0, chroma_js_1.default)(background).get('lab.l') < 70; return isDarkBackground ? 'inverse' : undefined; }; this.handleSubmit = (event) => { event.preventDefault(); if (this.props.allowEmptyStringSearch || this.state.searchQuery.trim()) { this.props.onSubmit(event); } else { this.focusInput(); } }; this.openCollapsedSearch = () => { if (this.props.isCollapsed && !this.state.showForm) { this.setState({ showForm: true }); } }; this.closeCollapsedSearch = () => { if (this.props.isCollapsed && this.state.showForm) { this.setState({ showForm: false }); } }; this.focusInput = () => { if (this.inputRef.current) { this.inputRef.current.focus(); } }; this.focusOpen = () => { if (this.openRef.current) { this.openRef.current.focus(); } }; this.handleFocus = () => { this.setState({ isFocused: true }); }; this.handleBlur = () => { this.setState({ isFocused: false }); }; this.handleSearchInputChange = (event) => { event.preventDefault(); this.setState({ searchQuery: event.target.value }); if (this.props.onInputChange) { this.props.onInputChange(event); } }; } componentDidUpdate(prevProps, prevState) { const showFormToggled = this.state.showForm !== prevState.showForm; if (showFormToggled) { if (this.state.showForm) { this.focusInput(); } else { this.focusOpen(); } } } render() { const { clearButtonAriaLabel = 'Reset Search Form', placeholder = 'Search', inputLabel = 'Search', submitAriaLabel = 'Search', openButtonAriaLabel = 'Open Search', closeButtonAriaLabel = 'Cancel', labelId = this.defaultLabelId, showClearButton = true, height = 40, grow, onSubmit, isCollapsed, onInputChange, autocompleteItems, initialValue, searchTheme, rightAlign, allowEmptyStringSearch = false, ...elemProps } = this.props; return (React.createElement(StyledSearchForm, { role: "search", action: ".", rightAlign: rightAlign, grow: grow, "aria-labelledby": labelId, isCollapsed: isCollapsed, onSubmit: this.handleSubmit, showForm: this.state.showForm, ...elemProps }, React.createElement(SearchContainer, { height: height }, React.createElement(SearchIcon, { "aria-label": submitAriaLabel, icon: canvas_system_icons_web_1.searchIcon, isCollapsed: isCollapsed, variant: this.getIconButtonType(), type: "submit", isHidden: !!isCollapsed && !this.state.showForm }), React.createElement(SearchIcon, { "aria-label": openButtonAriaLabel, icon: canvas_system_icons_web_1.searchIcon, isCollapsed: isCollapsed, variant: this.getIconButtonType(), onClick: this.openCollapsedSearch, ref: this.openRef, type: "button", isHidden: !isCollapsed || (!!isCollapsed && this.state.showForm) }), React.createElement(SearchField, { grow: grow, id: labelId, isCollapsed: isCollapsed, showForm: this.state.showForm, height: height }, React.createElement(form_field_1.FormField.Label, { cs: common_1.accessibleHideStyles }, inputLabel), React.createElement(SearchCombobox, { initialValue: initialValue, clearButtonVariant: this.getIconButtonType(), autocompleteItems: autocompleteItems, onChange: this.handleSearchInputChange, onFocus: this.handleFocus, onBlur: this.handleBlur, showClearButton: !isCollapsed && showClearButton, clearButtonAriaLabel: clearButtonAriaLabel, labelId: labelId }, React.createElement(form_field_1.FormField.Input, { as: SearchInput, ref: this.inputRef, cs: { maxWidth: grow ? '100%' : maxWidth }, value: this.state.searchQuery, placeholder: placeholder, isCollapsed: isCollapsed, inputColors: this.getThemeColors(), height: height, name: "search", autoComplete: "off" }))), React.createElement(CloseButton, { "aria-label": closeButtonAriaLabel, icon: canvas_system_icons_web_1.xIcon, isCollapsed: isCollapsed, showForm: this.state.showForm, onClick: this.closeCollapsedSearch, type: "button" })))); } } SearchForm.Theme = themes_1.SearchTheme; exports.SearchForm = SearchForm;