Skip to content

Commit

Permalink
update naming, clean up memo code
Browse files Browse the repository at this point in the history
  • Loading branch information
OskiTheCoder committed Oct 30, 2023
1 parent 077827b commit 1298252
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 130 deletions.
2 changes: 1 addition & 1 deletion .changeset/nasty-cups-trade.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"@easypost/easy-ui": minor
---

feat(SearchNav): support PrimaryCTAItem and EmphasizedText components
feat(SearchNav): support PrimaryCTAItem and Title components
2 changes: 1 addition & 1 deletion documentation/specs/SearchNav.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ A `SearchNav` is a navigation bar focused on handling dense information interact

`SearchNav` will be made up of sub-component containers. At the top level, the `SearchNav` serves as the container for the logo, dropdown, search input, and CTAs. The logo and dropdown will be grouped into a `SearchNav.LogoGroup` container. The search input will be wrapped by a `SearchNav.Search` container. The CTAs will be wrapped by a `SearchNav.CTAGroup` container.

`SearchNav.LogoGroup` will be comprised of `SearchNav.Logo`, a minimal wrapper for the consumer provided logo, `SearchNav.EmphasizedText`, and `SearchNav.Selector`. `SearchNav.Selector` will be built using React Aria's `useSelect`, `useListBox`, `usePopover`, `useOption` and `HiddenSelect`. To help manage state, it will also rely on React Stately's `useSelectState`.
`SearchNav.LogoGroup` will be comprised of `SearchNav.Logo`, a minimal wrapper for the consumer provided logo, `SearchNav.Title`, and `SearchNav.Selector`. `SearchNav.Selector` will be built using React Aria's `useSelect`, `useListBox`, `usePopover`, `useOption` and `HiddenSelect`. To help manage state, it will also rely on React Stately's `useSelectState`.

`SearchNav.CTAGroup` will render a primary CTA, `SearchNav.PrimaryCTAItem`, and a secondary CTA, `SearchNav.SecondaryCTAItem`; both will make use of Easy UI's `UnstyledButton` component.

Expand Down
8 changes: 8 additions & 0 deletions easy-ui-react/src/SearchNav/CTAGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ export type CTAGroupProps = {
children: ReactNode;
};

/**
*
* @privateRemarks
* This component doesn't directly use children and instead
* reads the nodes it renders from context. This is so we can
* efficiently share the same data across various configurations.
*
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function CTAGroup(_props: CTAGroupProps) {
const { menuOverlayProps, ctaMenuSymbol, primaryCTAItem, secondaryCTAItems } =
Expand Down
4 changes: 2 additions & 2 deletions easy-ui-react/src/SearchNav/CondensedSearchNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { getFlattenedKey } from "../utilities/react";
/**
* @privateRemarks
* Renders a left aligned menu button and right aligned search button.
* The menu options come from `SearchNav.Selector` and `SearchNav.CTAGroup`.
* On small screens, this effectively replaces `SearchNav`.
* The menu options come from `<SearchNav.Selector>` and `<SearchNav.CTAGroup>`.
* On small screens, this effectively replaces `<SearchNav>`.
*/
export function CondensedSearchNav() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
Expand Down
17 changes: 0 additions & 17 deletions easy-ui-react/src/SearchNav/EmphasizedText.tsx

This file was deleted.

14 changes: 11 additions & 3 deletions easy-ui-react/src/SearchNav/LogoGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,25 @@ export type LogoGroupProps = {
children: ReactNode;
};

/**
*
* @privateRemarks
* This component doesn't directly use children and instead
* reads the nodes it renders from context. This is so we can
* efficiently share the same data across various configurations.
*
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function LogoGroup(_props: LogoGroupProps) {
const { logo, emphasizedText, selector } = useInternalSearchNavContext();
const { logo, title, selector } = useInternalSearchNavContext();

return (
<div className={classNames(styles.logoGroup)}>
{logo}
{emphasizedText && (
{title && (
<>
<Separator group="logo" />
{emphasizedText}
{title}
</>
)}
{selector && (
Expand Down
6 changes: 3 additions & 3 deletions easy-ui-react/src/SearchNav/SearchNav.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ less than `640px`.

## Emphasized Text

<Canvas of={SearchNavStories.EmphasizedText} />
<Canvas of={SearchNavStories.Title} />

## Selector

Expand Down Expand Up @@ -97,9 +97,9 @@ export type SearchNavOverlayMenuProps<T> = {

<ArgTypes of={SearchNav.Logo} />

### SearchNav.EmphasizedText
### SearchNav.Title

<ArgTypes of={SearchNav.EmphasizedText} />
<ArgTypes of={SearchNav.Title} />

### SearchNav.Search

Expand Down
18 changes: 9 additions & 9 deletions easy-ui-react/src/SearchNav/SearchNav.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const Simple: Story = {
},
};

export const EmphasizedText: Story = {
export const Title: Story = {
render: Template.bind({}),
args: {
children: (
Expand All @@ -59,7 +59,7 @@ export const EmphasizedText: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
</SearchNav.LogoGroup>
</>
),
Expand All @@ -75,7 +75,7 @@ export const Selector: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
<SearchNav.Selector
aria-label="docs version"
defaultSelectedKey="V1.0"
Expand All @@ -102,7 +102,7 @@ export const SecondaryCTA: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
<SearchNav.Selector
aria-label="docs version"
defaultSelectedKey="V1.0"
Expand Down Expand Up @@ -150,7 +150,7 @@ export const PrimaryCTA: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
<SearchNav.Selector
aria-label="docs version"
defaultSelectedKey="V1.0"
Expand Down Expand Up @@ -199,11 +199,11 @@ export const Search: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
</SearchNav.LogoGroup>
<SearchNav.Search>
<PlaceholderBox width="100%" height={36}>
Search Bar
Search
</PlaceholderBox>
</SearchNav.Search>
<SearchNav.CTAGroup>
Expand All @@ -230,7 +230,7 @@ export const FullBar: Story = {
<SearchNav.Logo>
<EasyPostFullLogo />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
<SearchNav.Selector
aria-label="docs version"
defaultSelectedKey="V1.0"
Expand All @@ -245,7 +245,7 @@ export const FullBar: Story = {
</SearchNav.LogoGroup>
<SearchNav.Search>
<PlaceholderBox width="100%" height={36}>
Search Bar
Search
</PlaceholderBox>
</SearchNav.Search>
<SearchNav.CTAGroup>
Expand Down
6 changes: 3 additions & 3 deletions easy-ui-react/src/SearchNav/SearchNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ describe("<SearchNav />", () => {
);
});

it("should support rendering Search.EmphasizedText with appropriate styles", () => {
it("should support rendering Search.Title with appropriate styles", () => {
render(getSearchNav({}));
const emphasizedText = screen.getByText("DOCS");
const emphasizedText = screen.getByText("Docs");
expect(emphasizedText).toBeInTheDocument();
expect(emphasizedText).toHaveAttribute(
"class",
Expand Down Expand Up @@ -139,7 +139,7 @@ function getSearchNav({ selectorProps = {} }) {
<SearchNav.Logo>
<img alt="some logo" />
</SearchNav.Logo>
<SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
<SearchNav.Title>Docs</SearchNav.Title>
<SearchNav.Selector
aria-label="docs version"
defaultSelectedKey="V1.0"
Expand Down
119 changes: 29 additions & 90 deletions easy-ui-react/src/SearchNav/SearchNav.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import React, { ReactElement, ReactNode, useMemo } from "react";
import React, { ReactNode, useMemo } from "react";
import { classNames } from "../utilities/css";
import {
flattenChildren,
filterChildrenByDisplayName,
getDisplayNameFromReactNode,
} from "../utilities/react";
import { flattenChildren } from "../utilities/react";
import styles from "./SearchNav.module.scss";
import { LogoGroup } from "./LogoGroup";
import { Search } from "./Search";
Expand All @@ -18,7 +14,13 @@ import { SelectOption } from "../Select/SelectOption";
import { InternalSearchNavContext } from "./context";
import { IconSymbol } from "../types";
import { PrimaryCTAItem } from "./PrimaryCTAItem";
import { EmphasizedText } from "./EmphasizedText";
import { Title } from "./Title";
import {
getSearchChildren,
getCTAGroupChildren,
getLogoGroupChildren,
getSelectorLabel,
} from "./utilities";

export type SearchNavOverlayMenuProps<T> = Omit<
MenuOverlayProps<T>,
Expand Down Expand Up @@ -73,7 +75,7 @@ export type SearchNavProps<T> = {
* <SearchNav.Logo>
* <img alt="some logo" />
* </SearchNav.Logo>
* <SearchNav.EmphasizedText>DOCS</SearchNav.EmphasizedText>
* <SearchNav.Title>Docs</SearchNav.Title>
* <SearchNav.Selector
* label="docs version"
* defaultSelectedKey="V1.0"
Expand Down Expand Up @@ -111,98 +113,35 @@ export function SearchNav<T>(props: SearchNavProps<T>) {
const { menuOverlayProps, ctaMenuSymbol, children } = props;

const { onlyLogoGroup, context } = useMemo(() => {
// To support the various configurations on smaller screens,
// we extract data and nodes from the components provided
// by consumers and use context to share them efficiently.
const topLevelChildren = flattenChildren(children);

const logoGroupDisplayName = getDisplayNameFromReactNode(
const { logo, title, selector, selectorChildren } = getLogoGroupChildren(
topLevelChildren[0],
);
const selectorLabel = getSelectorLabel(selector);

if (logoGroupDisplayName !== "SearchNav.LogoGroup") {
throw new Error("SearchNav must contain SearchNav.LogoGroup.");
}
const logoGroupElement = topLevelChildren[0] as ReactElement;
const logoGroupChildren = flattenChildren(logoGroupElement.props.children);
const logoDisplayName = getDisplayNameFromReactNode(logoGroupChildren[0]);
if (logoDisplayName !== "SearchNav.Logo") {
throw new Error("SearchNav.LogoGroup must contain SearchNav.Logo.");
}
const logo = logoGroupChildren[0];

let emphasizedText;
if (
logoGroupChildren.length > 1 &&
getDisplayNameFromReactNode(logoGroupChildren[1]) ===
"SearchNav.EmphasizedText"
) {
emphasizedText = logoGroupChildren[1];
}

let selector;
let selectorChildren;
let selectorLabel = "";
if (
logoGroupChildren.length > 1 &&
getDisplayNameFromReactNode(
logoGroupChildren[logoGroupChildren.length - 1],
) === "SearchNav.Selector"
) {
selector = logoGroupChildren[logoGroupChildren.length - 1];
const selectorElem = selector as ReactElement;
const { "aria-label": label } = selectorElem.props;
selectorLabel = label;
selectorChildren = flattenChildren(selectorElem.props.children);
}
const search =
topLevelChildren.length > 1
? getSearchChildren(topLevelChildren[1])
: undefined;

let search;
if (
topLevelChildren.length > 1 &&
getDisplayNameFromReactNode(topLevelChildren[1]) === "SearchNav.Search"
) {
const searchChildren = flattenChildren(topLevelChildren[1]);
if (searchChildren.length === 1) {
search = searchChildren[0];
}
}

let secondaryCTAItems;
let primaryCTAItem;
let hasCtaGroup = false;
if (
topLevelChildren.length > 1 &&
getDisplayNameFromReactNode(
topLevelChildren[topLevelChildren.length - 1],
) === "SearchNav.CTAGroup"
) {
const ctaGroupElement = topLevelChildren[
topLevelChildren.length - 1
] as ReactElement;
hasCtaGroup = true;
secondaryCTAItems = filterChildrenByDisplayName(
ctaGroupElement.props.children,
"SearchNav.SecondaryCTAItem",
);
const primaryCTAItemArr = filterChildrenByDisplayName(
ctaGroupElement.props.children,
"SearchNav.PrimaryCTAItem",
);

if (primaryCTAItemArr.length > 1) {
throw new Error(
"SearchNav.CTAGroup can support at most one SearchNav.PrimaryCTAItem.",
);
}
if (primaryCTAItemArr.length !== 0) {
primaryCTAItem = primaryCTAItemArr[0];
}
}
const { secondaryCTAItems, primaryCTAItem } = getCTAGroupChildren(
topLevelChildren[topLevelChildren.length - 1],
);

const onlyLogoGroup = !hasCtaGroup && search === undefined;
const onlyLogoGroup =
secondaryCTAItems === undefined &&
primaryCTAItem === undefined &&
search === undefined;

return {
onlyLogoGroup,
context: {
logo,
emphasizedText,
title,
selector,
selectorChildren,
secondaryCTAItems,
Expand Down Expand Up @@ -250,12 +189,12 @@ SearchNav.LogoGroup = LogoGroup;
SearchNav.Logo = Logo;

/**
* Represents <SearchNav.EmphasizedText />`.
* Represents <SearchNav.Title />`.
*
* @remarks
* Renders emphasized text.
*/
SearchNav.EmphasizedText = EmphasizedText;
SearchNav.Title = Title;

/**
* Represents <SearchNav.Selector />`.
Expand Down
3 changes: 3 additions & 0 deletions easy-ui-react/src/SearchNav/Title.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.title {
text-transform: uppercase;
}
Loading

0 comments on commit 1298252

Please sign in to comment.