Skip to content

Commit

Permalink
feat: add panel component (#515)
Browse files Browse the repository at this point in the history
  • Loading branch information
NateWaldschmidt authored Jun 14, 2024
1 parent 48feccd commit d5d193b
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## v2.0.72

- Add `Panel` component

## v2.0.71

- Add `KeyValueInput` component
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lob/ui-components",
"version": "2.0.71",
"version": "2.0.72",
"engines": {
"node": ">=20.2.0",
"npm": ">=10.2.0"
Expand Down
7 changes: 7 additions & 0 deletions src/assets/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
@apply text-lg;
}

.uic-panel-container {
@apply rounded-md;
@apply border-line-grey border;
@apply bg-white;
@apply w-full p-4;
}

// TODO Move to `@layer components` when that works
.tile-container {
@apply rounded-2xl;
Expand Down
3 changes: 3 additions & 0 deletions src/components/Icon/svgs/Collapse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/components/Icon/svgs/CreditCardSearch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/components/Icon/svgs/Layers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion src/components/Icon/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ export const IconName = {
CLOUD_DATA: 'CloudData',
CODE: 'Code',
COIN: 'Coin',
COLLAPSE: 'Collapse',
COMMENT_NOTES: 'CommentNotes',
CREATIVE: 'Creative',
CREDIT_CARD: 'CreditCard',
CREDIT_CARD_SEARCH: 'CreditCardSearch',
DELETE: 'Delete',
DETAILS: 'Details',
DOLLAR_SIGN: 'DollarSign',
Expand All @@ -67,6 +69,7 @@ export const IconName = {
GIFT: 'Gift',
IMAGE_SEARCH: 'ImageSearch',
LAYER_GROUP: 'LayerGroup',
LAYERS: 'Layers',
LIGHTNING: 'Lightning',
LOCATION_PIN: 'LocationPin',
MONEY_BILL: 'MoneyBill',
Expand Down Expand Up @@ -121,6 +124,8 @@ export const IconSemantic = {
ROUTING_NUMBER: IconName.FILE_SHARE,
SEND_DATE: IconName.CALENDAR,
SIGNATORY: IconName.PEN,
TARGET_DELIVERY_DATE: IconName.CALENDAR_ALT
TARGET_DELIVERY_DATE: IconName.CALENDAR_ALT,
TEMPLATE_ID: IconName.CREDIT_CARD_SEARCH,
TEMPLATE_VERSION: IconName.LAYERS
} as const;
export type IconSemantic = (typeof IconSemantic)[keyof typeof IconSemantic];
10 changes: 10 additions & 0 deletions src/components/Panel/Panel.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Canvas, ArgTypes, PRIMARY_STORY } from '@storybook/addon-docs';
import { Primary } from './Panel.stories';

# Panel

<Canvas of={Primary} />

## Props

<ArgTypes story={PRIMARY_STORY} />
37 changes: 37 additions & 0 deletions src/components/Panel/Panel.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Meta, StoryFn } from '@storybook/vue3';
import mdx from './Panel.mdx';
// @ts-ignore No types from Vue file
import Panel from './Panel.vue';

const meta: Meta<typeof Panel> = {
title: 'Components/Panel',
component: Panel,
parameters: {
docs: {
page: mdx
}
}
};

export default meta;

const Template: StoryFn = (args, { argTypes }) => ({
components: { Panel },
setup: () => ({ args }),
template: `
<div style="width: 500px;">
<Panel v-bind="args">
<template #header>Metadata</template>
<template #default>
<ul>
<li>City: Chicago</li>
<li>State: Illinois</li>
<li>Country: United States</li>
</ul>
</template>
</Panel>
</div>
`
});

export const Primary = Template.bind({});
97 changes: 97 additions & 0 deletions src/components/Panel/Panel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<template>
<Panel
class="uic-panel-container"
:collapsed
data-testid="uic-panel"
:pt="{
transition: {
enterFromClass: 'max-h-0',
enterActiveClass:
'overflow-hidden transition-[max-height] duration-1000 ease-[cubic-bezier(0.42,0,0.58,1)]',
enterToClass: 'max-h-[1000px]',
leaveFromClass: 'max-h-[1000px]',
leaveActiveClass:
'overflow-hidden transition-[max-height] duration-[450ms] ease-[cubic-bezier(0,1,0,1)]',
leaveToClass: 'max-h-0'
}
}"
:toggleable="collapsible"
@update:collapsed="$emit('update:collapsed', $event)"
>
<template #header>
<component
:is="headerComponent"
class="type-base-600 flex flex-row gap-2 items-center"
>
<slot name="header">
{{ header }}
</slot>
<LoadingSpinnerIcon v-if="loading" />
</component>
</template>

<template #togglericon="{ collapsed: iconCollapsed }">
<Icon
:class="['toggle-icon', { collapsed: iconCollapsed }]"
data-testid="uic-panel-toggle-icon"
icon="Collapse"
size="lg"
/>
</template>

<template #default>
<slot />
</template>
</Panel>
</template>

<script setup lang="ts">
import { Icon } from '@/components/Icon';
import Panel from 'primevue/panel';
import { LoadingSpinnerIcon } from '../LoadingSpinnerIcon';
withDefaults(
defineProps<{
collapsed?: boolean;
collapsible?: boolean;
header?: string;
headerComponent?: string;
loading?: boolean;
}>(),
{
collapsed: false,
collapsible: false,
header: undefined,
headerComponent: 'h2',
loading: false
}
);
defineEmits<{
(e: 'update:collapsed', collapsed: boolean): void; // eslint-disable-line no-unused-vars
}>();
</script>

<style scoped="scss">
.uic-panel-container {
:deep([data-pc-section='header']) {
@apply flex flex-row gap-2 items-center justify-between;
}
:deep([data-pc-section='icons']) {
@apply flex flex-row items-center justify-center;
.toggle-icon {
transition: transform 0.3s;
&:not(.collapsed) {
transform: rotate(180deg);
}
}
}
:deep([data-pc-section='content']) {
@apply pt-2;
}
}
</style>
37 changes: 37 additions & 0 deletions src/components/Panel/__tests__/Panel.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import '@testing-library/jest-dom';
import userEvent from '@testing-library/user-event';
import { render, waitFor } from '@testing-library/vue';

import Panel from '../Panel.vue';

describe('Panel', () => {
it('renders', () => {
const { getByTestId, getByText } = render(Panel, {
slots: {
header: {
template: 'Test header slot'
},
default: {
template: 'Test default slot'
}
}
});

expect(getByTestId('uic-panel')).toBeVisible();
expect(getByText('Test header slot')).toBeVisible();
expect(getByText('Test default slot')).toBeVisible();
});

it('emits update:collapsed', async () => {
const { findByTestId, emitted } = render(Panel, {
props: {
collapsible: true
}
});

userEvent.click(await findByTestId('uic-panel-toggle-icon'));
await waitFor(() => {
expect(emitted()).toHaveProperty('update:collapsed');
});
});
});
1 change: 1 addition & 0 deletions src/components/Panel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Panel } from './Panel.vue';
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export * from './components/KeyValueInput';
export * from './components/Menu';
export * from './components/Modal';
export * from './components/Overlay';
export * from './components/Panel';
export * from './components/Pagination';
export * from './components/Steps';
export * from './components/Table';
Expand Down

0 comments on commit d5d193b

Please sign in to comment.