From 6dcb9aae429c6b842d959624168ab142416e505f Mon Sep 17 00:00:00 2001 From: Joshua Graber Date: Fri, 7 Jun 2024 07:15:41 -0400 Subject: [PATCH 1/2] chore(components): remove deprecated components BREAKING CHANGE: Above components removed from the component library. They will not be exported from this version. resolve #84 --- .../FlexContainer/FlexContainer.vue | 64 --------- .../__snapshots__/flex-container.spec.ts.snap | 3 - .../FlexContainer/flex-container.spec.ts | 37 ----- src/components/FlexContainer/index.ts | 3 - src/components/FlexContainer/types.ts | 4 - .../GridContainer/GridContainer.vue | 66 --------- .../__snapshots__/grid.spec.ts.snap | 9 -- src/components/GridContainer/grid.spec.ts | 136 ------------------ src/components/GridContainer/index.ts | 3 - src/components/GridContainer/types.ts | 7 - src/components/GridItem/GridItem.vue | 56 -------- src/components/GridItem/index.ts | 3 - src/components/GridItem/types.ts | 5 - src/components/index.ts | 3 - src/index.ts | 5 +- 15 files changed, 1 insertion(+), 403 deletions(-) delete mode 100644 src/components/FlexContainer/FlexContainer.vue delete mode 100644 src/components/FlexContainer/__snapshots__/flex-container.spec.ts.snap delete mode 100644 src/components/FlexContainer/flex-container.spec.ts delete mode 100644 src/components/FlexContainer/index.ts delete mode 100644 src/components/FlexContainer/types.ts delete mode 100644 src/components/GridContainer/GridContainer.vue delete mode 100644 src/components/GridContainer/__snapshots__/grid.spec.ts.snap delete mode 100644 src/components/GridContainer/grid.spec.ts delete mode 100644 src/components/GridContainer/index.ts delete mode 100644 src/components/GridContainer/types.ts delete mode 100644 src/components/GridItem/GridItem.vue delete mode 100644 src/components/GridItem/index.ts delete mode 100644 src/components/GridItem/types.ts diff --git a/src/components/FlexContainer/FlexContainer.vue b/src/components/FlexContainer/FlexContainer.vue deleted file mode 100644 index 6cb3ee9..0000000 --- a/src/components/FlexContainer/FlexContainer.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - diff --git a/src/components/FlexContainer/__snapshots__/flex-container.spec.ts.snap b/src/components/FlexContainer/__snapshots__/flex-container.spec.ts.snap deleted file mode 100644 index 5555488..0000000 --- a/src/components/FlexContainer/__snapshots__/flex-container.spec.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`Renders container component > Renders a container 1`] = `
Container Content
`; diff --git a/src/components/FlexContainer/flex-container.spec.ts b/src/components/FlexContainer/flex-container.spec.ts deleted file mode 100644 index 8aefe5a..0000000 --- a/src/components/FlexContainer/flex-container.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Component -import FlexContainer from './FlexContainer.vue'; - -// Utils -import { mount } from '@vue/test-utils'; -import { describe, expect, test } from 'vitest'; - -// Test -describe('Renders container component', () => { - // Render - test('Renders a container', () => { - const wrapper = mount(FlexContainer, { - slots: { - default: 'Container Content', - }, - }); - - expect(wrapper.find('.pdap-flex-container').exists()).toBe(true); - expect(wrapper.classes()).toContain('pdap-flex-container'); - expect(wrapper.html()).toContain('Container Content'); - expect(wrapper.html()).toMatchSnapshot(); - }); - - // Props - // Props - align - test('Renders start aligned container', () => { - const wrapper = mount(FlexContainer, { props: { alignment: 'start' } }); - expect(wrapper.props().alignment).toBe('start'); - expect(wrapper.classes()).toContain('pdap-flex-container-start'); - }); - - test('Renders center aligned container', () => { - const wrapper = mount(FlexContainer, { props: { alignment: 'center' } }); - expect(wrapper.props().alignment).toBe('center'); - expect(wrapper.classes()).toContain('pdap-flex-container-center'); - }); -}); diff --git a/src/components/FlexContainer/index.ts b/src/components/FlexContainer/index.ts deleted file mode 100644 index 785e98b..0000000 --- a/src/components/FlexContainer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import FlexContainer from './FlexContainer.vue'; - -export { FlexContainer }; diff --git a/src/components/FlexContainer/types.ts b/src/components/FlexContainer/types.ts deleted file mode 100644 index e1d831c..0000000 --- a/src/components/FlexContainer/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface PdapFlexContainerProps { - alignment?: 'center' | 'start'; - component?: string; -} diff --git a/src/components/GridContainer/GridContainer.vue b/src/components/GridContainer/GridContainer.vue deleted file mode 100644 index 58865d7..0000000 --- a/src/components/GridContainer/GridContainer.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - diff --git a/src/components/GridContainer/__snapshots__/grid.spec.ts.snap b/src/components/GridContainer/__snapshots__/grid.spec.ts.snap deleted file mode 100644 index 7b991e4..0000000 --- a/src/components/GridContainer/__snapshots__/grid.spec.ts.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`Renders container component > Renders a container 1`] = ` -
-
  • - - -
    -`; diff --git a/src/components/GridContainer/grid.spec.ts b/src/components/GridContainer/grid.spec.ts deleted file mode 100644 index b8ee539..0000000 --- a/src/components/GridContainer/grid.spec.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* eslint-disable vue/one-component-per-file */ -// Component -import GridContainer from './GridContainer.vue'; -import GridItem, { PdapGridItemProps } from '../GridItem/GridItem.vue'; - -// Utils -import { defineComponent } from 'vue'; -import { mount } from '@vue/test-utils'; -import { describe, expect, test, vi } from 'vitest'; - -type TestSlotProps = T; - -const data = [ - { component: 'li' }, - { component: 'img', src: 'https://mock.test.com' }, - { component: 'card', spanColumn: 3, spanRow: 2 }, -]; -const template = - ''; - -const expectComponents = new Set(['li', 'img', 'card']); - -const MultipleItems = defineComponent({ - components: { - GridItem, - }, - props: { - data: { - type: Array, - default: data, - }, - }, - template, -}); - -const SingleItem = defineComponent({ - components: { - GridItem, - }, - props: { - data: { - type: Array, - default: data, - }, - }, - template: '', -}); - -const getComputedStyle = vi.fn((el) => el.getComputedStyle()); -getComputedStyle.mockReturnValue({ - gridTemplateRows: 'repeat(3, minmax(20px, 1fr))', - gridTemplateColumns: 'repeat(2, auto)', - gridRow: 'span 2 / span 2', -}); -vi.stubGlobal('getComputedStyle', getComputedStyle); - -// Test -describe('Renders container component', () => { - // Render - test('Renders a container', () => { - const wrapper = mount(GridContainer, { - slots: { - default: MultipleItems, - }, - }); - - const container = wrapper.find('.pdap-grid-container'); - const items = container.findAll('.pdap-grid-item'); - - // Container - expect(container.exists()).toBe(true); - expect(wrapper.classes()).toContain('pdap-grid-container'); - - // Renders all items passed - expect(items.length).toBe(3); - - // Renders fall-through prop conditionally for img element - expect(container.find('[src="https://mock.test.com"]').exists()).toBe(true); - - // Renders each type of component passed - expect( - items.every((item) => - item.getRootNodes().some((node) => expectComponents.has(node.localName)) - ) - ).toBe(true); - - // Snapshot - expect(wrapper.html()).toMatchSnapshot(); - }); - - test('Renders a container with template props passed', () => { - const wrapper = mount(GridContainer, { - slots: { - default: MultipleItems, - }, - props: { - templateColumns: 'repeat(2, auto)', - templateRows: 'repeat(3, minmax(20px, 1fr))', - }, - }); - - expect(window.getComputedStyle(wrapper.vm.$el).gridTemplateColumns).toBe( - 'repeat(2, auto)' - ); - expect(window.getComputedStyle(wrapper.vm.$el).gridTemplateRows).toBe( - 'repeat(3, minmax(20px, 1fr))' - ); - }); - - test('Renders a container with columns and rows props passed', () => { - const wrapper = mount(GridContainer, { - slots: { - default: MultipleItems, - }, - props: { - rows: 2, - columns: 3, - }, - }); - - expect(wrapper.vm.$props.rows).toBe(2); - expect(wrapper.vm.$props.columns).toBe(3); - }); - - test('Renders a grid item with custom row span prop', () => { - const wrapper = mount(GridContainer, { - slots: { - default: SingleItem, - }, - }); - - expect( - window.getComputedStyle(wrapper.find('.pdap-grid-item').element).gridRow - ).toBe('span 2 / span 2'); - }); -}); diff --git a/src/components/GridContainer/index.ts b/src/components/GridContainer/index.ts deleted file mode 100644 index e407d59..0000000 --- a/src/components/GridContainer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import GridContainer from './GridContainer.vue'; - -export { GridContainer }; diff --git a/src/components/GridContainer/types.ts b/src/components/GridContainer/types.ts deleted file mode 100644 index 54eabca..0000000 --- a/src/components/GridContainer/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface PdapGridContainerProps { - columns?: 1 | 2 | 3 | 'auto'; - component?: string; - rows?: number | 'auto'; - templateColumns?: string; - templateRows?: string; -} diff --git a/src/components/GridItem/GridItem.vue b/src/components/GridItem/GridItem.vue deleted file mode 100644 index 79dd56a..0000000 --- a/src/components/GridItem/GridItem.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - diff --git a/src/components/GridItem/index.ts b/src/components/GridItem/index.ts deleted file mode 100644 index 2e0be61..0000000 --- a/src/components/GridItem/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import GridItem from './GridItem.vue'; - -export { GridItem }; diff --git a/src/components/GridItem/types.ts b/src/components/GridItem/types.ts deleted file mode 100644 index 70d1cd8..0000000 --- a/src/components/GridItem/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface PdapGridItemProps { - component?: string; - spanColumn?: 1 | 2 | 3; - spanRow?: number; -} diff --git a/src/components/index.ts b/src/components/index.ts index 4e6d2f6..7ae2708 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,9 +1,6 @@ export { Button } from './Button'; -export { FlexContainer } from './FlexContainer'; export { Footer } from './Footer'; export { Form } from './Form'; -export { GridContainer } from './GridContainer'; -export { GridItem } from './GridItem'; export { Input } from './Input'; export { Header } from './Header'; export { Nav } from './Nav'; diff --git a/src/index.ts b/src/index.ts index eb83c74..c64afa5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,14 @@ // Components export * from './components'; -// Styles +// Styles - compiled automatically import './styles/styles.css'; // Types export * from './components/Button/types'; export * from './components/Dropdown/types'; -export * from './components/FlexContainer/types'; export * from './components/Footer/types'; export * from './components/Form/types'; -export * from './components/GridContainer/types'; -export * from './components/GridItem/types'; export * from './components/Header/types'; export * from './components/Input/types'; export * from './components/Nav/types'; From 33f40b7ad7c438208603ed073813959dda8bc791 Mon Sep 17 00:00:00 2001 From: Joshua Graber Date: Fri, 7 Jun 2024 08:50:10 -0400 Subject: [PATCH 2/2] refactor(errorboundary): miscellaneous improvements add onError callback and error emit, forward params to fallback component --- .../ErrorBoundary/PdapErrorBoundary.vue | 71 ++++++++++++------- .../ErrorBoundary/error-boundary.spec.ts | 25 ++++++- src/components/ErrorBoundary/index.ts | 1 + src/components/ErrorBoundary/types.ts | 11 +++ src/components/index.ts | 1 + src/demo/pages/ComponentDemo.vue | 20 +++++- src/index.ts | 1 + 7 files changed, 102 insertions(+), 28 deletions(-) create mode 100644 src/components/ErrorBoundary/index.ts create mode 100644 src/components/ErrorBoundary/types.ts diff --git a/src/components/ErrorBoundary/PdapErrorBoundary.vue b/src/components/ErrorBoundary/PdapErrorBoundary.vue index f96cfe7..eee4ba5 100644 --- a/src/components/ErrorBoundary/PdapErrorBoundary.vue +++ b/src/components/ErrorBoundary/PdapErrorBoundary.vue @@ -1,8 +1,10 @@ - diff --git a/src/components/ErrorBoundary/error-boundary.spec.ts b/src/components/ErrorBoundary/error-boundary.spec.ts index 562f106..1310328 100644 --- a/src/components/ErrorBoundary/error-boundary.spec.ts +++ b/src/components/ErrorBoundary/error-boundary.spec.ts @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import { beforeEach, describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import ErrorBoundary from './PdapErrorBoundary.vue'; import { nextTick } from 'vue'; @@ -28,4 +28,27 @@ describe('ErrorBoundary', () => { ); expect(wrapper.html()).toMatchSnapshot(); }); + + it('calls the onError callback when an error occurs', async () => { + const onErrorSpy = vi.fn(); + + wrapper = mount(ErrorBoundary, { + props: { + onError: onErrorSpy, + }, + slots: { + default: '
    Default Content
    ', + }, + }); + + const testError = new Error('Test Error'); + wrapper.vm.interceptError(testError); + await nextTick(); + + expect(onErrorSpy).toHaveBeenCalledWith({ + error: testError, + vm: undefined, + info: undefined, + }); + }); }); diff --git a/src/components/ErrorBoundary/index.ts b/src/components/ErrorBoundary/index.ts new file mode 100644 index 0000000..0fac895 --- /dev/null +++ b/src/components/ErrorBoundary/index.ts @@ -0,0 +1 @@ +export { default as ErrorBoundary } from './PdapErrorBoundary.vue'; diff --git a/src/components/ErrorBoundary/types.ts b/src/components/ErrorBoundary/types.ts new file mode 100644 index 0000000..90a13c8 --- /dev/null +++ b/src/components/ErrorBoundary/types.ts @@ -0,0 +1,11 @@ +import { ComponentPublicInstance } from 'vue'; + +export interface PdapErrorBoundaryProps { + component: string; + onError?: ( + error: Error, + target?: ComponentPublicInstance | null | undefined + ) => void; + params?: Record; + stopPropagation?: boolean; +} diff --git a/src/components/index.ts b/src/components/index.ts index 7ae2708..4d15c5f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,5 @@ export { Button } from './Button'; +export { ErrorBoundary } from './ErrorBoundary'; export { Footer } from './Footer'; export { Form } from './Form'; export { Input } from './Input'; diff --git a/src/demo/pages/ComponentDemo.vue b/src/demo/pages/ComponentDemo.vue index b98a3d2..c45219c 100644 --- a/src/demo/pages/ComponentDemo.vue +++ b/src/demo/pages/ComponentDemo.vue @@ -144,7 +144,7 @@ -

    Here is a form using the Form component directly

    +

    Form

    Say hello
    -

    And here is the Quick Search Form component

    +

    Quick Search Form

    + +

    Error Boundary

    + +
    +

    + This is the content that will render inside the error boundary if + there is no error +

    + +
    +
    @@ -166,6 +177,7 @@ import { Breadcrumbs, Button, Dropdown, + ErrorBoundary, Form, QuickSearchForm, } from '../../components'; @@ -234,6 +246,10 @@ function buttonAlert(msg: string) { alert(msg); } +function triggerError() { + throw new Error('Trigger error fallback'); +} + function submit(values: Record<'firstName' | 'lastName' | 'iceCream', string>) { console.debug({ values }); const alertString = `Howdy, ${values.firstName} ${values.lastName}\n${ diff --git a/src/index.ts b/src/index.ts index c64afa5..cf2bcaf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ import './styles/styles.css'; // Types export * from './components/Button/types'; export * from './components/Dropdown/types'; +export * from './components/ErrorBoundary/types'; export * from './components/Footer/types'; export * from './components/Form/types'; export * from './components/Header/types';