Skip to content

Commit

Permalink
feat(components): dropdown (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuagraber committed Jun 3, 2024
1 parent b4c375f commit b29ef86
Show file tree
Hide file tree
Showing 14 changed files with 504 additions and 101 deletions.
133 changes: 41 additions & 92 deletions docs/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,38 @@ Documentation for PDAP component usage
- [Button](#button)

- [Props](#props-1)

- [Example](#example-1)

- [FlexContainer](#flexcontainer)

- [Props](#props-2)
- [Example](#example-2)
- [Props](#props-2)

- [Example](#example-2)

- [Footer](#footer)

- [Props](#props-3)
- [Example](#example-3)
- [Props](#props-3)

- [Example](#example-3)

- [Form](#form)

- [Props](#props-4)
- [Example](#example-4)
- [Props](#props-4)

- [Example](#example-4)

- [GridContainer](#gridcontainer)

- [Props](#props-5)
- [Example](#example-5)
- [Props](#props-5)

- [Example](#example-5)

- [GridItem](#griditem)

- [Props](#props-6)
- [Example](#example-6)
- [Props](#props-6)

- [Example](#example-6)

- [Header](#header)

Expand All @@ -48,109 +54,36 @@ Documentation for PDAP component usage

- [Nav](#nav)

- [Example](#example-8)
- [Example](#example-8)

- [QuickSearchForm](#quicksearchform)

- [Props](#props-8)
- [Props](#props-8)

- [TileIcon](#tileicon)

- [Props](#props-9)
- [Example](#example-9)

## Button
- [Props](#props-9)

### _Props_
- [Example](#example-9)

None
- [Dropdown](#dropdown)

### _Example_
- [Props](#props-9)

See the Demo application [page](../src/demo/pages/ComponentDemo.vue) and [router](../src/demo/router.js)
- [Example](#example-9)

## Button

### _Props_

name | required? | types | description | default
----------- | --------- | ----------- | ------------- | --------------------------
`isLoading` | no | `boolean` | Request state | `false`
`intent` | yes | `primary` \ | `secondary` | Determines style of button | `primary`

### _Example_

```
<template>
<Button class="custom-btn-class" intent="primary" @click="() => console.log('hello world')" type="button">Click me</Button>
</template>
...
<script>
import { Button } from 'pdap-design-system';
...
export default {
components: ['Button'],
...
}
</script>
...
<style>
.custom-btn-class {
padding: 12px;
}
</style>
```

## FlexContainer

_DEPRECATED_ All container components are designed to be dynamic and take any `HTMLElement` tag as the component to be rendered. `FlexContainer` can itself be passed as the element type for `GridItem`, for example, or vice versa, allowing us to easily compose complex layouts (more on this later with the `GridContainer` and `GridItem` documentation).

### _Props_

name | required? | types | description | default
----------- | --------- | --------- | ----------------------------------- | ----------------------
`component` | no | `string` | HTML Element to render as container | `'div'`
`alignment` | no | `start` \ | `center` | Flex alignment presets | `start`
None

### _Example_

```
<template>
<FlexContainer alignment="center" component="card">
<h2>Some content goes here</h2>
<p>More content goes here.</p>
<Button class="custom-button-class-name" :isLoading="isLoading" @click="() => console.log('hello world')">
Say hello with this button
</Button>
</FlexContainer>
</template>
...
<script>
import { Button, FlexContainer } from 'pdap-design-system';
See the Demo application [page](../src/demo/pages/ComponentDemo.vue) and [router](../src/demo/router.js)

...

export default {
components: ['Button', 'FlexContainer'],
props: ['requestPending', ...],
data() {
return {
isLoading: this.requestPending
}
}
...
}
</script>
```

## Footer

### _Props_
Expand Down Expand Up @@ -582,3 +515,19 @@ export default {
}
</script>
```

## Dropdown

The Dropdown component is an accessible dropdown menu that can be triggered by click or hover and positioned in various placements. It provides keyboard accessibility features such as toggling the dropdown on enter/space and closing on escape.

### _Props_

name | required? | types | description | default
------------- | --------- | ------------------------- | -------------------------------------------------- | -------------------------------
`defaultOpen` | no | `boolean` | Whether the dropdown is initially open | `false`
`disabled` | no | `boolean` | Whether the dropdown should be disabled | `false`
`triggerType` | no | `PdapDropdownTriggerType` | The type of event that should trigger the dropdown | `PdapDropdownTriggerType.PRESS`

### _Example_

See [Component demo](../src/demo/pages/ComponentDemo.vue)
12 changes: 6 additions & 6 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
Expand Up @@ -134,4 +134,4 @@
"path": "./node_modules/cz-conventional-changelog"
}
}
}
}
89 changes: 89 additions & 0 deletions src/components/Dropdown/PdapDropdown.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { shallowMount } from '@vue/test-utils';
import PdapDropdown from './PdapDropdown.vue';
import { PdapDropdownTriggerType } from './types';

let wrapper;
let trigger;
let content;

describe('PdapDropdown', () => {
beforeEach(() => {
wrapper = shallowMount(PdapDropdown, {
slots: {
trigger: 'Toggle Dropdown',
content: '<ul><li>Option 1</li><li>Option 2</li><li>Option 3</li></ul>',
},
attachTo: document.body,
});

trigger = wrapper.find('[data-test="dropdown-trigger"]');
content = wrapper.find('[data-test="dropdown-content"]');
});

it('should open and close dropdown correctly', async () => {
expect(content.isVisible()).toBe(false);

await trigger.trigger('click');
expect(content.isVisible()).toBe(true);

await trigger.trigger('click');
expect(content.isVisible()).toBe(false);
expect(wrapper.html()).toMatchSnapshot();
});

it('should be accessible with keyboard', async () => {
expect(content.isVisible()).toBe(false);

await trigger.trigger('keydown.enter');
expect(content.isVisible()).toBe(true);

await trigger.trigger('keydown.escape');
expect(content.isVisible()).toBe(false);

expect(wrapper.html()).toMatchSnapshot();
});

it('should respect disabled prop', async () => {
wrapper = shallowMount(PdapDropdown, {
props: {
disabled: true,
},
slots: {
trigger: 'Toggle Dropdown',
content: '<ul><li>Option 1</li><li>Option 2</li><li>Option 3</li></ul>',
},
attachTo: document.body,
});
trigger = wrapper.find('[data-test="dropdown-trigger"]');
content = wrapper.find('[data-test="dropdown-content"]');

await trigger.trigger('click');
expect(content.isVisible()).toBe(false);

expect(wrapper.html()).toMatchSnapshot();
});

it('should respect the triggerOn prop', async () => {
wrapper = shallowMount(PdapDropdown, {
props: {
triggerOn: PdapDropdownTriggerType.HOVER,
},
slots: {
trigger: 'Toggle Dropdown',
content: '<ul><li>Option 1</li><li>Option 2</li><li>Option 3</li></ul>',
},
attachTo: document.body,
});
trigger = wrapper.find('[data-test="dropdown-trigger"]');
content = wrapper.find('[data-test="dropdown-content"]');

await trigger.trigger('focusin');
expect(content.isVisible()).toBe(true);

await trigger.trigger('focusout');
expect(content.isVisible()).toBe(false);

expect(wrapper.html()).toMatchSnapshot();
});
});
Loading

0 comments on commit b29ef86

Please sign in to comment.