@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
JavaScript
"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;