Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
f8135d0
add naive process & icon list React components
Jun 21, 2022
5519601
add new copy (english)
Jun 21, 2022
0984795
no identity-doc-auth gem anymore
Jun 21, 2022
31ea8fe
add welcome step (will rename)
Jun 21, 2022
6dae588
add WelcomeStep to the flow
Jun 21, 2022
58b1faf
organize list components into directories
Jun 21, 2022
b646be5
rename ipp/welcome to ipp/prepare
Jun 21, 2022
23b40f3
finish styling prepare component
Jun 22, 2022
38c5e4a
cleanup
Jun 22, 2022
001db33
add placement location page
Jun 22, 2022
3414b74
new component for submit button in troubleshooting
Jun 23, 2022
7858f0f
LG-6087: Update IPP flow button styles to match accompanying links
NavaTim Jun 24, 2022
8209620
LG-6087: Update IPP flow button styles to override other styles more …
NavaTim Jun 24, 2022
dd25c1e
LG-6087: Fix minor issues with IPP button styling changes
NavaTim Jun 24, 2022
5ec4fca
refactor new components
Jun 27, 2022
0046960
skip unnecessary logic
Jun 27, 2022
90b9c72
remove errors
Jun 27, 2022
027b25e
collapse icon & process list components
Jun 27, 2022
4e0f0a9
remove location & prepare steps
Jun 27, 2022
0952c36
placement French & Spanish translations
Jun 27, 2022
193bfb9
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jun 27, 2022
09236c9
clean up new steps
Jun 28, 2022
d44243c
gate inclusion of in person steps
Jun 28, 2022
f98aa1d
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jun 29, 2022
455db4e
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jun 29, 2022
4fbe237
fix scss formatting
Jun 29, 2022
d4f6d84
remove unused annotations
Jun 29, 2022
a71df2b
small troubleshooting options refactor
Jun 30, 2022
a70db95
url is optional
Jun 30, 2022
7b861a4
click continue to go to in person flow
Jun 30, 2022
04bf8d3
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jun 30, 2022
49f5abf
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jul 7, 2022
054e427
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jul 10, 2022
ba91aea
allow steps to tell FormSteps they're complete
Jul 10, 2022
4c07cbe
remove unload protection when leaving prep step
Jul 10, 2022
5fa4687
fix linting errors
Jul 10, 2022
3240e31
fix tests
Jul 10, 2022
5ec5d15
fix lint errors on test file
Jul 10, 2022
ef79a6d
normalize yaml
Jul 11, 2022
6fe4f9f
add changelog
Jul 11, 2022
82d1b9f
tests for new components
Jul 11, 2022
65664ff
remove tabIndex
Jul 11, 2022
590b475
rename style & target selectors we're overriding
Jul 11, 2022
ac32914
no className param in components that don't use it
Jul 13, 2022
c45132a
rename stepIsComplete to stepCanComplete
Jul 13, 2022
06f40f9
reset hash in URL if there is no matching step
Jul 13, 2022
f208acd
test for button type
Jul 13, 2022
2a37cb9
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jul 13, 2022
73179dc
wrap stepName reset in useEffect
Jul 13, 2022
32c2939
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jul 13, 2022
bcb422e
move styles into icon list components statically
Jul 14, 2022
a61875d
allow IPP help center URL
Jul 14, 2022
ba18ea8
Merge remote-tracking branch 'origin/main' into tomas/lg-6087-build-v…
Jul 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/assets/stylesheets/components/_block-submit-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.block-submit-button {
cursor: pointer;

&.usa-button--unstyled {
display: block;
line-height: 1.5;

&:hover,
&:active {
text-decoration: none;
}

&:focus {
outline: none;
}
}
}
1 change: 1 addition & 0 deletions app/assets/stylesheets/components/all.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import 'account-header';
@import 'banner';
@import 'block-link';
@import 'block-submit-button';
@import 'btn';
@import 'card';
@import 'container';
Expand Down
18 changes: 18 additions & 0 deletions app/javascript/packages/components/block-link-arrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function BlockLinkArrow() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 5.2 8.91"
focusable="false"
aria-hidden="true"
className="block-link__arrow"
>
<path
d="M5.11 4.66L1 8.82a.36.36 0 01-.21.09.31.31 0 01-.2-.09l-.5-.45a.29.29 0 01-.09-.2A.36.36 0 01.09 8L3.6 4.45.09 1A.36.36 0 010 .74a.31.31 0 01.09-.2L.54.09A.31.31 0 01.74 0 .36.36 0 011 .09l4.11 4.16a.31.31 0 01.09.2.31.31 0 01-.09.21z"
fill="currentColor"
/>
</svg>
);
}

export default BlockLinkArrow;
14 changes: 2 additions & 12 deletions app/javascript/packages/components/block-link.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Link, { LinkProps } from './link';
import BlockLinkArrow from './block-link-arrow';

export interface BlockLinkProps extends LinkProps {
/**
Expand All @@ -13,18 +14,7 @@ function BlockLink({ href, children, className, ...linkProps }: BlockLinkProps)
return (
<Link href={href} {...linkProps} className={classes}>
{children}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 5.2 8.91"
focusable="false"
aria-hidden="true"
className="block-link__arrow"
>
<path
d="M5.11 4.66L1 8.82a.36.36 0 01-.21.09.31.31 0 01-.2-.09l-.5-.45a.29.29 0 01-.09-.2A.36.36 0 01.09 8L3.6 4.45.09 1A.36.36 0 010 .74a.31.31 0 01.09-.2L.54.09A.31.31 0 01.74 0 .36.36 0 011 .09l4.11 4.16a.31.31 0 01.09.2.31.31 0 01-.09.21z"
fill="currentColor"
/>
</svg>
<BlockLinkArrow />
</Link>
);
}
Expand Down
30 changes: 30 additions & 0 deletions app/javascript/packages/components/block-submit-button.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { render } from '@testing-library/react';
import BlockSubmitButton from './block-submit-button';

describe('BlockSubmitButton', () => {
const buttonLabel = 'Click here to submit';

it('renders a button with an expected class name, type, and arrow content', () => {
const { getByRole } = render(<BlockSubmitButton>{buttonLabel}</BlockSubmitButton>);

const button = getByRole('button') as HTMLInputElement;

expect(button.classList.contains('block-submit-button')).to.be.true();
expect(button.querySelector('.block-link__arrow')).to.exist();
expect(button.textContent).to.equal(buttonLabel);
expect(button.type).to.equal('submit');
});

context('with custom css class', () => {
it('renders a link with passed class name', () => {
const { getByRole } = render(
<BlockSubmitButton className="my-custom-class">{buttonLabel}</BlockSubmitButton>,
);

const button = getByRole('button');

expect(button.classList.contains('block-submit-button')).to.be.true();
expect(button.classList.contains('my-custom-class')).to.be.true();
});
});
});
36 changes: 36 additions & 0 deletions app/javascript/packages/components/block-submit-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { ReactNode } from 'react';
import BlockLinkArrow from './block-link-arrow';

interface BlockSubmitButtonProps extends React.ComponentPropsWithoutRef<'button'> {
/**
* Link text.
*/
children?: ReactNode;

/**
* Additional class names to apply.
*/
className?: string;
}

function BlockSubmitButton({ children, className, ...linkProps }: BlockSubmitButtonProps) {
const classes = [
'block-submit-button',
'usa-button--unstyled',
'usa-link',
'block-link',
'width-full',
className,
]
.filter(Boolean)
.join(' ');

return (
<button type="submit" {...linkProps} className={classes}>
{children}
<BlockLinkArrow />
</button>
);
}

export default BlockSubmitButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { render } from '@testing-library/react';
import IconListContent from './icon-list-content';

describe('IconListContent', () => {
it('renders the component with expected class and children', () => {
const { getByText } = render(
<IconListContent>
<div>Example</div>
</IconListContent>,
);

const child = getByText('Example');
const item = child.parentElement!;

expect(item.classList.contains('usa-icon-list__content')).to.be.true();
expect(item.textContent).to.equal('Example');
});
});
13 changes: 13 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ReactNode } from 'react';

interface IconListContentProps {
children?: ReactNode;
}

function IconListContent({ children }: IconListContentProps) {
const classes = 'usa-icon-list__content';

return <div className={classes}>{children}</div>;
}

export default IconListContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { render } from '@testing-library/react';
import IconListIcon from './icon-list-icon';

describe('IconListIcon', () => {
it('renders the component with expected class and children', () => {
const { getByText } = render(
<IconListIcon className="example-class">
<div>Example</div>
</IconListIcon>,
);

const child = getByText('Example');
const item = child.parentElement!;

expect(item.classList.contains('usa-icon-list__icon')).to.be.true();
expect(item.classList.contains('example-class')).to.be.true();
expect(item.textContent).to.equal('Example');
});
});
15 changes: 15 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { ReactNode } from 'react';

interface IconListIconProps {
children?: ReactNode;

className?: string;
}

function IconListIcon({ children, className }: IconListIconProps) {
const classes = ['usa-icon-list__icon', 'text-primary-dark', className].filter(Boolean).join(' ');

return <div className={classes}>{children}</div>;
}

export default IconListIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { render } from '@testing-library/react';
import IconListItem from './icon-list-item';

describe('IconListItem', () => {
it('renders the component with expected class and children', () => {
const { container } = render(
<IconListItem icon="check_circle" title="Example title">
<div>Example</div>
</IconListItem>,
);

const wrapper = container.firstElementChild!;
expect(wrapper.classList.contains('usa-icon-list__item')).to.be.true();

const iconListIcon = wrapper.firstElementChild!;
expect(iconListIcon.classList.contains('usa-icon-list__icon')).to.be.true();
const icon = iconListIcon.firstElementChild!;
expect(icon.classList.contains('usa-icon')).to.be.true();
const iconListContent = iconListIcon.nextElementSibling!;
expect(iconListContent.classList.contains('usa-icon-list__content')).to.be.true();
const iconListTitle = iconListContent.firstElementChild!;
expect(iconListTitle.classList.contains('usa-icon-list__title')).to.be.true();
expect(iconListTitle.textContent).to.equal('Example title');
const child = iconListTitle.nextElementSibling!;
expect(child.textContent).to.equal('Example');
});
});
29 changes: 29 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Icon, IconListContent, IconListIcon, IconListTitle } from '@18f/identity-components';
import type { ReactNode } from 'react';
import type { DesignSystemIcon } from '../icon';

interface IconListItemProps {
children?: ReactNode;

icon: DesignSystemIcon;

title: string;
}

function IconListItem({ children, icon, title }: IconListItemProps) {
const classes = 'usa-icon-list__item';

return (
<li className={classes}>
<IconListIcon>
<Icon icon={icon} />
</IconListIcon>
<IconListContent>
<IconListTitle>{title}</IconListTitle>
{children}
</IconListContent>
</li>
);
}

export default IconListItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { render } from '@testing-library/react';
import IconListTitle from './icon-list-title';

describe('IconListTitle', () => {
it('renders the component with expected class and children', () => {
const { getByText } = render(
<IconListTitle>
<div>Example</div>
</IconListTitle>,
);

const child = getByText('Example');
const item = child.parentElement!;

expect(item.classList.contains('usa-icon-list__title')).to.be.true();
expect(item.textContent).to.equal('Example');
});
});
17 changes: 17 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list-title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ReactNode } from 'react';

interface IconListTitleProps {
children?: ReactNode;

className?: string;
}

function IconListTitle({ children, className }: IconListTitleProps) {
const classes = ['usa-icon-list__title', 'font-sans-md', 'padding-top-0', className]
.filter(Boolean)
.join(' ');

return <h3 className={classes}>{children}</h3>;
}

export default IconListTitle;
18 changes: 18 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { render } from '@testing-library/react';
import IconList from './icon-list';

describe('IconList', () => {
it('renders the component with expected class and children', () => {
const { getByText } = render(
<IconList>
<div>Example</div>
</IconList>,
);

const child = getByText('Example');
const item = child.parentElement!;

expect(item.classList.contains('usa-icon-list')).to.be.true();
expect(item.textContent).to.equal('Example');
});
});
13 changes: 13 additions & 0 deletions app/javascript/packages/components/icon-list/icon-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ReactNode } from 'react';

interface IconListProps {
children?: ReactNode;
}

function IconList({ children }: IconListProps) {
const classes = 'usa-icon-list';

return <ul className={classes}>{children}</ul>;
}

export default IconList;
13 changes: 11 additions & 2 deletions app/javascript/packages/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
export { default as Accordion } from './accordion';
export { default as Alert } from './alert';
export { default as Button } from './button';
export { default as BlockLink } from './block-link';
export { default as Icon } from './icon';
export { default as BlockSubmitButton } from './block-submit-button';
export { default as Button } from './button';
export { default as FullScreen } from './full-screen';
export { default as Icon } from './icon';
export { default as IconList } from './icon-list/icon-list';
export { default as IconListContent } from './icon-list/icon-list-content';
export { default as IconListIcon } from './icon-list/icon-list-icon';
export { default as IconListItem } from './icon-list/icon-list-item';
export { default as IconListTitle } from './icon-list/icon-list-title';
export { default as Link } from './link';
export { default as PageFooter } from './page-footer';
export { default as PageHeading } from './page-heading';
export { default as ProcessList } from './process-list/process-list';
export { default as ProcessListHeading } from './process-list/process-list-heading';
export { default as ProcessListItem } from './process-list/process-list-item';
export { default as ScrollIntoView } from './scroll-into-view';
export { default as SpinnerDots } from './spinner-dots';
export { default as StatusPage } from './status-page';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { render } from '@testing-library/react';
import ProcessListHeading from './process-list-heading';

describe('ProcessListHeading', () => {
it('renders the component with expected class and children', () => {
const { getByText } = render(
<ProcessListHeading>
<li>Example</li>
</ProcessListHeading>,
);

const child = getByText('Example');
const item = child.parentElement!;

expect(item.classList.contains('usa-process-list__heading')).to.be.true();
expect(item.textContent).to.equal('Example');
});

it('renders the component with no class if unstyled is passed', () => {
const { container } = render(
<ProcessListHeading unstyled>
<li>Example</li>
</ProcessListHeading>,
);

const item = container.firstElementChild!;

expect(item.classList).to.be.empty();
});
});
Loading