@workday/canvas-kit-docs
Version:
Documentation components of Canvas Kit components
150 lines (149 loc) • 8.46 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import * as React from 'react';
import { AccessibleHide, AriaLiveRegion, composeHooks, createComponent, createElemPropsHook, createSubcomponent, useUniqueId, } from '@workday/canvas-kit-react/common';
import { system } from '@workday/canvas-tokens-web';
import { calc, createStyles, px2rem } from '@workday/canvas-kit-styling';
import { notificationsIcon, inboxIcon, justifyIcon, assistantIcon, searchIcon, } from '@workday/canvas-system-icons-web';
import { SecondaryButton, TertiaryButton } from '@workday/canvas-kit-react/button';
import { Avatar } from '@workday/canvas-kit-preview-react/avatar';
import { Flex } from '@workday/canvas-kit-react/layout';
import { Tooltip } from '@workday/canvas-kit-react/tooltip';
import { Combobox, useComboboxModel, useComboboxInput, useComboboxLoader, } from '@workday/canvas-kit-react/combobox';
import { InputGroup, TextInput } from '@workday/canvas-kit-react/text-input';
import { StyledMenuItem } from '@workday/canvas-kit-react/menu';
import { SystemIcon } from '@workday/canvas-kit-react/icon';
import { CountBadge } from '@workday/canvas-kit-react/badge';
const tasks = ['Request Time Off', 'Create Expense Report', 'Change Benefits'];
const styleOverrides = {
headerWrapper: createStyles({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
boxSizing: 'border-box',
...system.type.subtext.large,
WebkitFontSmoothing: 'antialiased',
MozOsxFontSmoothing: 'grayscale',
backgroundColor: system.color.bg.default,
padding: system.space.x1,
}),
flexItems: createStyles({
gap: system.space.x4,
alignItems: 'center',
marginX: system.space.x3,
}),
inputGroupInner: createStyles({
marginLeft: '1rem',
width: px2rem(20),
transition: 'opacity 100ms ease',
}),
comboboxContainer: createStyles({
margin: 'auto',
width: '100%',
maxWidth: calc.multiply(system.space.x20, 6),
}),
comboboxInput: createStyles({
borderRadius: px2rem(1000),
width: '20rem',
}),
comboboxMenuList: createStyles({
maxHeight: px2rem(200),
}),
menuButtonStyles: createStyles({
textDecoration: 'none',
color: system.color.fg.strong,
}),
notificationContainerStyles: createStyles({
boxSizing: 'border-box',
position: 'relative',
}),
countBadgeStyles: createStyles({
boxSizing: 'border-box',
position: 'absolute',
top: calc.negate(system.space.x1),
insetInlineEnd: calc.negate(system.space.x1),
}),
actionButtonStyles: createStyles({
gap: system.space.x4,
margin: system.space.x4,
}),
};
const useAutocompleteInput = composeHooks(createElemPropsHook(useComboboxModel)(model => {
return {
onKeyPress(event) {
model.events.show(event);
},
};
}), useComboboxInput);
const AutoCompleteInput = createSubcomponent(TextInput)({
modelHook: useComboboxModel,
elemPropsHook: useAutocompleteInput,
})((elemProps, Element) => {
return _jsx(Combobox.Input, { as: Element, ...elemProps });
});
export const Basic = () => {
const [notifications, setNotifications] = React.useState(0);
function handleAdd() {
setNotifications(prev => prev + 1);
}
function handleClear() {
setNotifications(0);
}
return (_jsxs("header", { children: [_jsx(GlobalHeader, { notifications: notifications }), _jsxs(Flex, { cs: styleOverrides.actionButtonStyles, children: [_jsx(SecondaryButton, { onClick: handleAdd, children: "Add notification" }), _jsx(TertiaryButton, { onClick: handleClear, children: "Clear" })] })] }));
};
export const GlobalHeader = createComponent('div')({
displayName: 'GlobalHeader',
Component: ({ notifications, ...props }) => (_jsxs("div", { className: styleOverrides.headerWrapper, children: [_jsxs(Flex, { cs: styleOverrides.flexItems, children: [_jsx(Tooltip, { title: "Global Navigation", type: "describe", children: _jsx(TertiaryButton, { icon: justifyIcon, cs: styleOverrides.menuButtonStyles, children: "MENU" }) }), _jsx(Tooltip, { title: "Workday Home", children: _jsx(TertiaryButton, { children: _jsx("img", { src: "https://design.workday.com/images/ck-dub-logo-blue.svg", alt: "" }) }) })] }), _jsx(Flex, { cs: styleOverrides.flexItems, children: _jsx(Autocomplete, { "aria-label": "Search Workday" }) }), _jsxs(Flex, { cs: styleOverrides.flexItems, children: [_jsx(Tooltip, { title: "Assistant", children: _jsx(TertiaryButton, { icon: assistantIcon }) }), _jsx(NotificationLiveBadge, { cnt: notifications }), _jsx(Tooltip, { title: "My Tasks", children: _jsx(TertiaryButton, { icon: inboxIcon }) }), _jsx(Tooltip, { title: "Profile", children: _jsx(Avatar, { name: "Logan McNeil", isDecorative: true }) })] })] })),
});
const Autocomplete = createComponent('div')({
displayName: 'Autocomplete',
Component: props => {
const [searchText, setSearchText] = React.useState('');
function handleChange(e) {
setSearchText(e.target.value);
}
const { model, loader } = useComboboxLoader({
// You can start with any number that makes sense.
total: 0,
// Pick whatever number makes sense for your API
pageSize: 20,
// A load function that will be called by the loader. You must return a promise that returns
// an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache
async load({ pageNumber, pageSize, filter }) {
return new Promise(resolve => {
// simulate a server response by resolving after a period of time
setTimeout(() => {
// simulate paging and filtering based on pre-computed items
const start = (pageNumber - 1) * pageSize;
const end = start + pageSize;
const filteredTasks = tasks.filter(i => {
if (searchText.trim() === '' || typeof searchText !== 'string') {
return true;
}
return i.toLowerCase().includes(searchText.trim().toLowerCase());
});
const total = filteredTasks.length;
const items = filteredTasks.slice(start, end);
resolve({
items,
total,
});
}, 300);
});
},
onShow() {
// The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is
// visible
loader.load();
},
}, useComboboxModel);
return (_jsxs(Combobox, { model: model, children: [_jsxs(InputGroup, { children: [_jsx(InputGroup.InnerStart, { cs: styleOverrides.inputGroupInner, children: _jsx(SystemIcon, { icon: searchIcon }) }), _jsx(InputGroup.Input, { as: AutoCompleteInput, cs: styleOverrides.comboboxInput, onChange: handleChange, value: searchText, ...props })] }), _jsx(Combobox.Menu.Popper, { children: _jsx(Combobox.Menu.Card, { children: model.state.items.length === 0 ? (_jsx(StyledMenuItem, { as: "span", children: "No Results Found" })) : (model.state.items.length > 0 && (_jsx(Combobox.Menu.List, { maxHeight: px2rem(200), children: item => _jsx(Combobox.Menu.Item, { children: item }) }))) }) })] }));
},
});
const NotificationLiveBadge = createComponent('span')({
displayName: 'NotificationLiveBadge',
Component: ({ cnt = 0, ...props }) => {
const btnId = useUniqueId();
const badgeId = useUniqueId();
return (_jsxs(Flex, { cs: styleOverrides.notificationContainerStyles, children: [_jsx(Tooltip, { title: "Notifications", children: _jsx(TertiaryButton, { id: btnId, icon: notificationsIcon, "aria-describedby": cnt > 0 ? badgeId : undefined, ...props }) }), _jsx(AriaLiveRegion, { "aria-labelledby": btnId, children: cnt > 0 && (_jsxs(_Fragment, { children: [_jsx(CountBadge, { id: badgeId, count: cnt, limit: 100, cs: styleOverrides.countBadgeStyles }), _jsx(AccessibleHide, { children: "New" })] })) })] }));
},
});