diff --git a/package.json b/package.json index 29f860e..86f16d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vectara/vectara-ui", - "version": "1.0.1", + "version": "2.3.0", "homepage": "https://vectara.github.io/vectara-ui/", "description": "Vectara's design system, codified as a React and Sass component library", "author": "Vectara", diff --git a/src/docs/Docs.tsx b/src/docs/Docs.tsx index cf49daa..d78f738 100644 --- a/src/docs/Docs.tsx +++ b/src/docs/Docs.tsx @@ -81,6 +81,7 @@ const DocsContent = () => { target="_blank" color="neutral" size="m" + aria-label="Vectara UI GitHub repository" icon={ diff --git a/src/docs/Page.tsx b/src/docs/Page.tsx index 7f9f57a..10ee859 100644 --- a/src/docs/Page.tsx +++ b/src/docs/Page.tsx @@ -31,6 +31,7 @@ export const Page = ({ name, examples }: { name: string; examples: ExampleType[] @@ -42,8 +43,8 @@ export const Page = ({ name, examples }: { name: string; examples: ExampleType[] - {" "} diff --git a/src/docs/pages.tsx b/src/docs/pages.tsx index c0a0e6a..ddc2940 100644 --- a/src/docs/pages.tsx +++ b/src/docs/pages.tsx @@ -1,6 +1,5 @@ // Components import { accordion } from "./pages/accordion"; -import { accountMenu } from "./pages/accountMenu"; import { app } from "./pages/app"; import { badge } from "./pages/badge"; import { button } from "./pages/button"; @@ -16,6 +15,8 @@ import { formGroup } from "./pages/formGroup"; import { grid } from "./pages/grid"; import { horizontalRule } from "./pages/horizontalRule"; import { icon } from "./pages/icon"; +import { infoList } from "./pages/infoList"; +import { infoMenu } from "./pages/infoMenu"; import { infoTable } from "./pages/infoTable"; import { input } from "./pages/input"; import { label } from "./pages/label"; @@ -63,15 +64,15 @@ export const categories: Category[] = [ }, { name: "Application", - pages: [app, accountMenu, drawer, modal, notifications] + pages: [app, drawer, modal, notifications] }, { name: "Info", - pages: [table, infoTable, statList, list] + pages: [table, infoTable, infoList, statList, list] }, { name: "Layout", - pages: [tabs, accordion, popover, flex, grid, spacer, card, horizontalRule] + pages: [tabs, accordion, popover, infoMenu, flex, grid, spacer, card, horizontalRule] }, { name: "Content", diff --git a/src/docs/pages/button/IconButton.tsx b/src/docs/pages/button/IconButton.tsx index b3244a1..9370b0b 100644 --- a/src/docs/pages/button/IconButton.tsx +++ b/src/docs/pages/button/IconButton.tsx @@ -21,7 +21,14 @@ export const IconButton = () => { {BUTTON_COLOR.map((color) => ( - + console.log("click")} + onMouseOver={() => console.log("mouse over")} + onMouseOut={() => console.log("mouse out")} + /> ))} @@ -31,7 +38,7 @@ export const IconButton = () => { {BUTTON_SIZE.map((size) => ( - + ))} diff --git a/src/docs/pages/button/Link.tsx b/src/docs/pages/button/Link.tsx index be1a815..07f0cfa 100644 --- a/src/docs/pages/button/Link.tsx +++ b/src/docs/pages/button/Link.tsx @@ -2,7 +2,14 @@ import { VuiButtonPrimary } from "../../../lib"; export const Link = () => { return ( - + console.log("click")} + onMouseOver={() => console.log("mouse over")} + onMouseOut={() => console.log("mouse out")} + > Visit Vectara.com ); diff --git a/src/docs/pages/button/Sizes.tsx b/src/docs/pages/button/Sizes.tsx index 2f4ad8c..d6e820f 100644 --- a/src/docs/pages/button/Sizes.tsx +++ b/src/docs/pages/button/Sizes.tsx @@ -32,7 +32,15 @@ export const Sizes = () => { {BUTTON_SIZE.map((size) => ( - + console.log("click")} + onMouseOver={() => console.log("mouse over")} + onMouseOut={() => console.log("mouse out")} + > Size {size} diff --git a/src/docs/pages/infoList/InfoList.tsx b/src/docs/pages/infoList/InfoList.tsx new file mode 100644 index 0000000..fca4508 --- /dev/null +++ b/src/docs/pages/infoList/InfoList.tsx @@ -0,0 +1,28 @@ +import { VuiButtonSecondary, VuiSpacer, VuiText, VuiInfoList } from "../../../lib"; + +export const InfoList = () => { + return ( + + +

22 MB

+
+ + + + + Refresh + + + ) + } + ]} + /> + ); +}; diff --git a/src/docs/pages/infoList/index.tsx b/src/docs/pages/infoList/index.tsx new file mode 100644 index 0000000..b200922 --- /dev/null +++ b/src/docs/pages/infoList/index.tsx @@ -0,0 +1,13 @@ +import { InfoList } from "./InfoList"; +const InfoListSource = require("!!raw-loader!./InfoList"); + +export const infoList = { + name: "Info List", + path: "/InfoList", + examples: [ + { + component: , + source: InfoListSource.default.toString() + } + ] +}; diff --git a/src/docs/pages/infoMenu/InfoMenu.tsx b/src/docs/pages/infoMenu/InfoMenu.tsx new file mode 100644 index 0000000..733c3be --- /dev/null +++ b/src/docs/pages/infoMenu/InfoMenu.tsx @@ -0,0 +1,62 @@ +import { useState } from "react"; +import { VuiInfoMenu, VuiButtonSecondary, VuiIcon, VuiOptionsList, VuiSpacer, VuiText } from "../../../lib"; +import { BiSolidUser } from "react-icons/bi"; + +const options = [ + { value: "edit", label: "Update profile" }, + { value: "signOut", label: "Sign out" } +]; + +export const InfoMenu = () => { + const [isOpen, setIsOpen] = useState(false); + + return ( + + +
+ } + > + email@email.com + + } + info={[ + { title: "Email", value: "email@email.com" }, + { title: "Account number", value: "1234567890" }, + { + title: "Account size", + value: ( + <> + +

22 MB

+
+ + + + + Refresh + + + ) + } + ]} + > + { + alert(`Selected ${value}`); + }} + options={options} + size="l" + /> + + ); +}; diff --git a/src/docs/pages/infoMenu/index.tsx b/src/docs/pages/infoMenu/index.tsx new file mode 100644 index 0000000..287eda2 --- /dev/null +++ b/src/docs/pages/infoMenu/index.tsx @@ -0,0 +1,13 @@ +import { InfoMenu } from "./InfoMenu"; +const InfoMenuSource = require("!!raw-loader!./InfoMenu"); + +export const infoMenu = { + name: "Info Menu", + path: "/InfoMenu", + examples: [ + { + component: , + source: InfoMenuSource.default.toString() + } + ] +}; diff --git a/src/docs/pages/modal/PrimaryModal.tsx b/src/docs/pages/modal/PrimaryModal.tsx index 5a8eb38..1e1a145 100644 --- a/src/docs/pages/modal/PrimaryModal.tsx +++ b/src/docs/pages/modal/PrimaryModal.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { VuiButtonPrimary, VuiButtonSecondary, VuiModal, VuiSearchSelect, VuiSpacer, VuiText } from "../../../lib"; +import { BiInfoCircle } from "react-icons/bi"; const options = [ { value: "a", label: "Caffeine-free" }, @@ -27,7 +28,7 @@ export const PrimaryModal = () => { Open primary modal - setIsOpen(false)} title="FYI"> + setIsOpen(false)} icon={} title="FYI">

I just thought you should know that your modal is showing.

diff --git a/src/docs/pages/popover/Popover.tsx b/src/docs/pages/popover/Popover.tsx index 12f161b..54fc603 100644 --- a/src/docs/pages/popover/Popover.tsx +++ b/src/docs/pages/popover/Popover.tsx @@ -1,5 +1,14 @@ import { useState } from "react"; -import { VuiButtonSecondary, VuiIcon, VuiOptionsList, VuiPopover } from "../../../lib"; +import { + AnchorSide, + VuiButtonSecondary, + VuiFormGroup, + VuiIcon, + VuiOptionsList, + VuiPopover, + VuiSelect, + VuiSpacer +} from "../../../lib"; import { BiCaretDown } from "react-icons/bi"; const options = [ @@ -11,36 +20,54 @@ const options = [ export const Popover = () => { const [isOpen, setIsOpen] = useState(false); const [selectedOption, setSelectedOption] = useState("apples"); + const [anchorSide, setAnchorSide] = useState("right"); return ( - setIsOpen(!isOpen)} - header="Tribes" - button={ - - - - } - > - Tribe: {selectedOption} - - } - > - { - setIsOpen(false); - setSelectedOption(value); - }} - selected={selectedOption} - options={options} - /> - + <> + + setAnchorSide(event.target.value as AnchorSide)} + /> + + + + + setIsOpen(!isOpen)} + header="Tribes" + button={ + + + + } + > + Tribe: {selectedOption} + + } + > + { + setIsOpen(false); + setSelectedOption(value); + }} + selected={selectedOption} + options={options} + /> + + ); }; diff --git a/src/docs/pages/searchSelect/SingleSelect.tsx b/src/docs/pages/searchSelect/SingleSelect.tsx new file mode 100644 index 0000000..5032eac --- /dev/null +++ b/src/docs/pages/searchSelect/SingleSelect.tsx @@ -0,0 +1,43 @@ +import { useState } from "react"; +import { VuiButtonSecondary, VuiSearchSelect } from "../../../lib"; + +const options = [ + { value: "a", label: "Caffeine-free" }, + { value: "b", label: "Freeze dried" }, + { value: "c", label: "Gluten-free" }, + { value: "d", label: "Halal" }, + { value: "e", label: "High fiber" }, + { value: "f", label: "Kosher" }, + { value: "g", label: "Lactose-free" }, + { value: "h", label: "Low-carb" }, + { value: "i", label: "No nuts" }, + { value: "j", label: "Non-GMO" }, + { value: "k", label: "Sugar-free" }, + { value: "l", label: "Vegan" } +]; + +export const SingleSelect = () => { + const [isOpen, setIsOpen] = useState(false); + const [searchValue, setSearchValue] = useState(""); + const [selectedOptions, setSelectedOptions] = useState(["a"]); + + return ( + { + setSelectedOptions(value); + }} + selectedOptions={selectedOptions} + options={options} + isMultiSelect={false} + > + + Meal preference + + + ); +}; diff --git a/src/docs/pages/searchSelect/index.tsx b/src/docs/pages/searchSelect/index.tsx index 3c2fab1..1e8f8af 100644 --- a/src/docs/pages/searchSelect/index.tsx +++ b/src/docs/pages/searchSelect/index.tsx @@ -1,20 +1,29 @@ import { SearchSelect } from "./SearchSelect"; import { Async } from "./Async"; +import { SingleSelect } from "./SingleSelect"; const SearchSelectSource = require("!!raw-loader!./SearchSelect"); const AsyncSource = require("!!raw-loader!./Async"); +const SingleSelectSource = require("!!raw-loader!./SingleSelect"); export const searchSelect = { name: "Search Select", path: "/searchSelect", examples: [ { + name: "Synchronous search", component: , source: SearchSelectSource.default.toString() }, { + name: "Asynchronous search", component: , source: AsyncSource.default.toString() + }, + { + name: "Single selection", + component: , + source: SingleSelectSource.default.toString() } ] }; diff --git a/src/docs/pages/table/Table.tsx b/src/docs/pages/table/Table.tsx index 9572b4f..653da21 100644 --- a/src/docs/pages/table/Table.tsx +++ b/src/docs/pages/table/Table.tsx @@ -233,11 +233,11 @@ export const Table = () => { const search = canSearch ? { - searchValue, - searchPlaceholder: "Search people", - onSearchChange: (search: string) => { + value: searchValue, + placeholder: "Search people", + onChange: (e: React.ChangeEvent) => { setCurrentPage(1); - setSearchValue(search); + setSearchValue(e.target.value); } } : undefined; diff --git a/src/lib/components/app/appSideNav/AppSideNav.tsx b/src/lib/components/app/appSideNav/AppSideNav.tsx index 022a78a..19f5989 100644 --- a/src/lib/components/app/appSideNav/AppSideNav.tsx +++ b/src/lib/components/app/appSideNav/AppSideNav.tsx @@ -56,7 +56,7 @@ export const VuiAppSideNav = ({ items = [], content }: Props) => { {isCollapsed ? ( setIsCollapsed(false)} className="vuiAppSideNavExpandButton" color="neutral" diff --git a/src/lib/components/app/appSideNav/AppSideNavTree.tsx b/src/lib/components/app/appSideNav/AppSideNavTree.tsx index 18c7643..e4d87df 100644 --- a/src/lib/components/app/appSideNav/AppSideNavTree.tsx +++ b/src/lib/components/app/appSideNav/AppSideNavTree.tsx @@ -70,6 +70,7 @@ const AppSideNavTreeSection = ({ name, path, children, iconBefore, iconAfter, is /> setIsOpen(!isOpen)} diff --git a/src/lib/components/button/BaseButton.tsx b/src/lib/components/button/BaseButton.tsx index 8d5b0d4..32b81a2 100644 --- a/src/lib/components/button/BaseButton.tsx +++ b/src/lib/components/button/BaseButton.tsx @@ -31,7 +31,10 @@ export type BaseButtonProps = { isSelected?: boolean; isInert?: boolean; isDisabled?: boolean; - onClick?: (e: React.MouseEvent) => void; + onClick?: React.MouseEventHandler; + onMouseOver?: React.MouseEventHandler; + onMouseOut?: React.MouseEventHandler; + onMouseMove?: React.MouseEventHandler; href?: LinkProps["href"]; target?: LinkProps["target"]; track?: LinkProps["track"]; @@ -57,6 +60,9 @@ export const BaseButton = forwardRef( size = "m", fullWidth, onClick, + onMouseOver, + onMouseOut, + onMouseMove, tabIndex, isInert, isDisabled, @@ -112,6 +118,9 @@ export const BaseButton = forwardRef( className: wrapperClasses, href, onClick, + onMouseOver, + onMouseOut, + onMouseMove, children: ( //* Wrap a button otherwise the flex layout breaks */}