@kiva/kv-components 3.50.0 → 3.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.52.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.51.0...@kiva/kv-components@3.52.0) (2024-01-31)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * added missing suppression classes ([5d04867](https://github.com/kiva/kv-ui-elements/commit/5d048672f078d2d229372e37b896c9be025457d9))
12
+
13
+
14
+ ### Features
15
+
16
+ * add comments add component ([1bf5fc3](https://github.com/kiva/kv-ui-elements/commit/1bf5fc388fee61a63f49775a15b50728c140a569))
17
+
18
+
19
+
20
+
21
+
22
+ # [3.51.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.50.0...@kiva/kv-components@3.51.0) (2024-01-25)
23
+
24
+
25
+ ### Features
26
+
27
+ * add basic comments container for future comment work ([4f1b3ab](https://github.com/kiva/kv-ui-elements/commit/4f1b3aba7f78ead3cf53a955bbb1b1243c4b2cda))
28
+
29
+
30
+
31
+
32
+
6
33
  # [3.50.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.49.1...@kiva/kv-components@3.50.0) (2024-01-19)
7
34
 
8
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kiva/kv-components",
3
- "version": "3.50.0",
3
+ "version": "3.52.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -75,5 +75,5 @@
75
75
  "optional": true
76
76
  }
77
77
  },
78
- "gitHead": "7bedad99cec599d99830aeebedfc9d49f4f53649"
78
+ "gitHead": "185baa28a3a0e9616ca3ef4cf404b9074d19b373"
79
79
  }
@@ -0,0 +1,74 @@
1
+ import { render } from '@testing-library/vue';
2
+ import userEvent from '@testing-library/user-event';
3
+ import CommentsAdd, { ADD_COMMENT_EVENT } from '../../../../vue/KvCommentsAdd.vue';
4
+
5
+ const renderCommentsAdd = (props = {}) => {
6
+ return render(CommentsAdd, { props });
7
+ };
8
+
9
+ describe('KvCommentsAdd', () => {
10
+ it('should render defaults', () => {
11
+ const { getByPlaceholderText, getByRole } = renderCommentsAdd();
12
+ getByPlaceholderText('Add a comment to this loan...');
13
+ getByRole('button', { name: 'Cancel' });
14
+ getByRole('button', { name: 'Comment' });
15
+ });
16
+
17
+ it('should render user info', () => {
18
+ const { getByAltText, getByText } = renderCommentsAdd({
19
+ userImageUrl: 'test.com',
20
+ userDisplayName: 'User',
21
+ });
22
+ getByAltText('Lender');
23
+ getByText('User');
24
+ });
25
+
26
+ it('should enable comment button when text entered', async () => {
27
+ const { getByPlaceholderText, getByRole } = renderCommentsAdd();
28
+ const textInput = getByPlaceholderText('Add a comment to this loan...');
29
+ const commentButton = getByRole('button', { name: 'Comment' });
30
+
31
+ expect(commentButton.disabled).toBeTruthy();
32
+
33
+ await userEvent.type(textInput, 'test');
34
+
35
+ expect(commentButton.disabled).toBeFalsy();
36
+
37
+ await userEvent.clear(textInput);
38
+
39
+ expect(commentButton.disabled).toBeTruthy();
40
+ });
41
+
42
+ it('should clear text when cancel clicked', async () => {
43
+ const { getByPlaceholderText, getByRole } = renderCommentsAdd();
44
+ const textInput = getByPlaceholderText('Add a comment to this loan...');
45
+ const cancelButton = getByRole('button', { name: 'Cancel' });
46
+
47
+ await userEvent.type(textInput, 'test');
48
+ await userEvent.click(cancelButton);
49
+
50
+ expect(textInput.value).toBe('');
51
+ });
52
+
53
+ it('should emit value when comment clicked', async () => {
54
+ const { getByPlaceholderText, getByRole, emitted } = renderCommentsAdd();
55
+ const textInput = getByPlaceholderText('Add a comment to this loan...');
56
+ const commentButton = getByRole('button', { name: 'Comment' });
57
+ const TEST_INPUT = 'test test';
58
+
59
+ await userEvent.type(textInput, TEST_INPUT);
60
+
61
+ await userEvent.click(commentButton);
62
+
63
+ expect(emitted()[ADD_COMMENT_EVENT]).toEqual([[TEST_INPUT]]);
64
+ });
65
+
66
+ it('should not emit empty value when comment clicked', async () => {
67
+ const { getByRole, emitted } = renderCommentsAdd();
68
+ const commentButton = getByRole('button', { name: 'Comment' });
69
+
70
+ await userEvent.click(commentButton);
71
+
72
+ expect(emitted()[ADD_COMMENT_EVENT]).toBe(undefined);
73
+ });
74
+ });
@@ -0,0 +1,28 @@
1
+ import { render } from '@testing-library/vue';
2
+ import userEvent from '@testing-library/user-event';
3
+ import Container from '../../../../vue/KvCommentsContainer.vue';
4
+ import { ADD_COMMENT_ID, ADD_COMMENT_EVENT } from '../../../../vue/KvCommentsAdd.vue';
5
+
6
+ const renderContainer = (props = {}) => {
7
+ return render(Container, { props });
8
+ };
9
+
10
+ describe('KvCommentsContainer', () => {
11
+ it('should render comments add component', async () => {
12
+ const { container } = renderContainer();
13
+ expect(container.querySelectorAll(`#${ADD_COMMENT_ID}`).length).toBe(1);
14
+ });
15
+
16
+ it('should emit comment', async () => {
17
+ const { getByPlaceholderText, getByRole, emitted } = renderContainer();
18
+ const textInput = getByPlaceholderText('Add a comment to this loan...');
19
+ const commentButton = getByRole('button', { name: 'Comment' });
20
+ const TEST_INPUT = 'test test';
21
+
22
+ await userEvent.type(textInput, TEST_INPUT);
23
+
24
+ await userEvent.click(commentButton);
25
+
26
+ expect(emitted()[ADD_COMMENT_EVENT]).toEqual([[TEST_INPUT]]);
27
+ });
28
+ });
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <div class="tw-flex tw-flex-col">
3
+ <div class="tw-flex tw-flex-col md:tw-flex-row md:tw-items-center tw-gap-0.5 md:tw-gap-1">
4
+ <div class="tw-flex tw-items-center tw-gap-1">
5
+ <img
6
+ v-if="userImageUrl"
7
+ :src="userImageUrl"
8
+ alt="Lender"
9
+ class="
10
+ data-hj-suppress
11
+ tw-inline-block
12
+ tw-w-3.5
13
+ tw-h-3.5
14
+ tw-rounded-full
15
+ tw-overflow-hidden
16
+ tw-object-fill
17
+ "
18
+ >
19
+ <div class="data-hj-suppress tw-font-medium">
20
+ {{ userDisplayName }}
21
+ </div>
22
+ </div>
23
+ <kv-text-input
24
+ :id="ADD_COMMENT_ID"
25
+ v-model="addCommentValue"
26
+ placeholder="Add a comment to this loan..."
27
+ class="data-hj-suppress tw-grow"
28
+ />
29
+ </div>
30
+ <div class="tw-flex tw-py-0.5 tw-gap-0.5">
31
+ <kv-button
32
+ variant="ghost"
33
+ class="tw-ml-auto"
34
+ @click="cancel"
35
+ >
36
+ Cancel
37
+ </kv-button>
38
+ <kv-button
39
+ variant="ghost"
40
+ :state="commentButtonState"
41
+ @click="comment"
42
+ >
43
+ Comment
44
+ </kv-button>
45
+ </div>
46
+ </div>
47
+ </template>
48
+
49
+ <script>
50
+ import { computed, ref } from 'vue-demi';
51
+ import KvButton from './KvButton.vue';
52
+ import KvTextInput from './KvTextInput.vue';
53
+
54
+ export const ADD_COMMENT_ID = 'add-comment-value';
55
+ export const ADD_COMMENT_EVENT = 'add-comment';
56
+
57
+ export default {
58
+ components: {
59
+ KvButton,
60
+ KvTextInput,
61
+ },
62
+ props: {
63
+ /**
64
+ * The full URL for the user image
65
+ */
66
+ userImageUrl: {
67
+ type: String,
68
+ default: '',
69
+ },
70
+ /**
71
+ * The name to display for the user
72
+ */
73
+ userDisplayName: {
74
+ type: String,
75
+ default: '',
76
+ },
77
+ },
78
+ emits: [ADD_COMMENT_EVENT],
79
+ setup(_props, { emit }) {
80
+ const addCommentValue = ref('');
81
+
82
+ const commentButtonState = computed(() => (addCommentValue.value ? '' : 'disabled'));
83
+
84
+ const cancel = () => {
85
+ addCommentValue.value = '';
86
+ };
87
+
88
+ const comment = () => {
89
+ emit(ADD_COMMENT_EVENT, addCommentValue.value);
90
+ };
91
+
92
+ return {
93
+ ADD_COMMENT_ID,
94
+ addCommentValue,
95
+ commentButtonState,
96
+ cancel,
97
+ comment,
98
+ };
99
+ },
100
+ };
101
+ </script>
102
+
103
+ <style lang="postcss" scoped>
104
+ >>> input {
105
+ @apply tw-border-t-0 tw-border-r-0 tw-border-l-0 tw-rounded-none tw-p-0 tw-h-4;
106
+ }
107
+
108
+ >>> input:focus {
109
+ @apply tw-border-tertiary;
110
+ box-shadow: none;
111
+ }
112
+
113
+ >>> button > span {
114
+ @apply tw-min-h-0;
115
+ }
116
+
117
+ >>> button > span > span {
118
+ @apply tw-py-0 tw-px-0.5;
119
+ }
120
+ </style>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <kv-comments-add
3
+ :user-image-url="userImageUrl"
4
+ :user-display-name="userDisplayName"
5
+ @add-comment="comment"
6
+ />
7
+ </template>
8
+
9
+ <script>
10
+ import KvCommentsAdd from './KvCommentsAdd.vue';
11
+
12
+ export const ADD_COMMENT_EVENT = 'add-comment';
13
+
14
+ export default {
15
+ components: {
16
+ KvCommentsAdd,
17
+ },
18
+ props: {
19
+ /**
20
+ * The full URL for the user image
21
+ */
22
+ userImageUrl: {
23
+ type: String,
24
+ default: '',
25
+ },
26
+ /**
27
+ * The name to display for the user
28
+ */
29
+ userDisplayName: {
30
+ type: String,
31
+ default: '',
32
+ },
33
+ },
34
+ setup(_props, { emit }) {
35
+ const comment = (commentValue) => {
36
+ emit(ADD_COMMENT_EVENT, commentValue);
37
+ };
38
+
39
+ return {
40
+ comment,
41
+ };
42
+ },
43
+ };
44
+ </script>
@@ -0,0 +1,32 @@
1
+ import KvCommentsAdd from '../KvCommentsAdd.vue';
2
+
3
+ export default {
4
+ title: 'KvCommentsAdd',
5
+ component: KvCommentsAdd,
6
+ };
7
+
8
+ const story = (args) => {
9
+ const template = (templateArgs, { argTypes }) => ({
10
+ props: Object.keys(argTypes),
11
+ components: { KvCommentsAdd },
12
+ setup() { return { args: templateArgs }; },
13
+ template: `
14
+ <div style="max-width: 800px;">
15
+ <KvCommentsAdd v-bind="args" />
16
+ </div>
17
+ `,
18
+ });
19
+ template.args = args;
20
+ return template;
21
+ };
22
+
23
+ export const Default = story({});
24
+
25
+ export const UserName = story({
26
+ userDisplayName: 'User',
27
+ });
28
+
29
+ export const UserInfo = story({
30
+ userImageUrl: 'https://via.placeholder.com/50x50',
31
+ userDisplayName: 'User',
32
+ });
@@ -0,0 +1,23 @@
1
+ import KvCommentsContainer from '../KvCommentsContainer.vue';
2
+
3
+ export default {
4
+ title: 'KvCommentsContainer',
5
+ component: KvCommentsContainer,
6
+ };
7
+
8
+ const story = (args) => {
9
+ const template = (templateArgs, { argTypes }) => ({
10
+ props: Object.keys(argTypes),
11
+ components: { KvCommentsContainer },
12
+ setup() { return { args: templateArgs }; },
13
+ template: `
14
+ <div style="max-width: 800px;">
15
+ <KvCommentsContainer v-bind="args" />
16
+ </div>
17
+ `,
18
+ });
19
+ template.args = args;
20
+ return template;
21
+ };
22
+
23
+ export const Default = story({});