@usssa/component-library 1.0.0-alpha.116 → 1.0.0-alpha.118

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Component Library v1.0.0-alpha.116
1
+ # Component Library v1.0.0-alpha.118
2
2
 
3
3
  **This library provides custom UI components for USSSA applications.**
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usssa/component-library",
3
- "version": "1.0.0-alpha.116",
3
+ "version": "1.0.0-alpha.118",
4
4
  "description": "A Quasar component library project",
5
5
  "productName": "Quasar component library App",
6
6
  "author": "Troy Moreland <troy.moreland@usssa.com>",
@@ -1,58 +1,62 @@
1
1
  <script setup>
2
- import { computed, ref } from 'vue'
3
2
  import UAvatar from './UAvatar.vue'
4
- import UBtnStd from './UBtnStd.vue'
5
3
  import UBtnIcon from './UBtnIcon.vue'
4
+ import UBtnStd from './UBtnStd.vue'
5
+
6
+ const emit = defineEmits(['update-country', 'onClick'])
6
7
 
7
8
  const props = defineProps({
8
- color: {
9
+ anchor: {
9
10
  type: String,
10
11
  },
11
- label: {
12
- type: String
12
+ ariaLabel: {
13
+ type: String,
13
14
  },
14
- iconClass: {
15
+ avatarUrl: {
15
16
  type: String,
16
17
  },
17
- size: {
18
+ color: {
18
19
  type: String,
19
- default: 'md',
20
- validator: (val) => ['sm', 'md', 'lg'].includes(val),
21
20
  },
22
- states: {
21
+ dataTestId: {
23
22
  type: String,
24
- default: 'Basic',
25
- validator: (val) => ['Basic', 'Icon', 'Button', 'Avatar', 'Prefix'].includes(val),
23
+ default: 'menu-button',
26
24
  },
27
- selectedCountry: {
28
- type: Object,
25
+ displayName: {
26
+ type: String,
29
27
  },
30
- tooltip: {
28
+ iconClass: {
31
29
  type: String,
32
30
  },
33
- anchor: {
31
+ label: {
34
32
  type: String,
35
33
  },
34
+ menuOffset: {
35
+ type: Array,
36
+ default: () => [4, 4],
37
+ },
38
+ selectedCountry: {
39
+ type: Object,
40
+ },
36
41
  self: {
37
42
  type: String,
38
43
  },
39
- displayName: {
44
+ size: {
40
45
  type: String,
46
+ default: 'md',
47
+ validator: (val) => ['sm', 'md', 'lg'].includes(val),
41
48
  },
42
- avatarUrl: {
43
- type: String,
44
- },
45
- ariaLabel: {
49
+ states: {
46
50
  type: String,
51
+ default: 'Basic',
52
+ validator: (val) =>
53
+ ['Basic', 'Icon', 'Button', 'Avatar', 'Prefix'].includes(val),
47
54
  },
48
- menuOffset: {
49
- type: Array,
50
- default: () => [4, 4],
55
+ tooltip: {
56
+ type: String,
51
57
  },
52
58
  })
53
59
 
54
- const emit = defineEmits(['update-country', 'onClick'])
55
-
56
60
  const handleClick = () => {
57
61
  return emit('onClick')
58
62
  }
@@ -63,47 +67,43 @@ const toLowerCase = (str) => str.toLowerCase()
63
67
  </script>
64
68
 
65
69
  <template>
66
-
67
70
  <!-- 1. Menu button Basic state -->
68
71
  <q-btn-dropdown
69
72
  v-if="states === 'Basic'"
70
- :aria-label="label"
71
73
  :class="`u-mb-btn u-mb-basic size-${size}`"
74
+ :aria-label="label"
72
75
  :color="color"
76
+ :dataTestId="dataTestId"
73
77
  flat
74
78
  :menu-offset="menuOffset"
75
79
  no-caps
76
- text-color='dark'
80
+ text-color="dark"
77
81
  >
78
82
  <template #label>
79
- <q-icon
80
- v-if="iconClass"
81
- :class="iconClass"
82
- size='sm'
83
- />
83
+ <q-icon v-if="iconClass" :class="iconClass" size="sm" />
84
84
  <div class="text-body-md q-ml-xs">{{ label }}</div>
85
85
  </template>
86
- <slot name='menu' />
86
+ <slot name="menu" />
87
87
  </q-btn-dropdown>
88
-
89
-
88
+
90
89
  <!-- 2. Menu button Icon state -->
91
90
  <UBtnIcon
92
91
  v-if="states === 'Icon'"
93
- :ariaLabel="ariaLabel"
94
- :anchor="anchor"
95
92
  class="u-mb-icon"
93
+ :anchor="anchor"
94
+ :ariaLabel="ariaLabel"
96
95
  :color="color"
96
+ :dataTestId="dataTestId"
97
97
  :iconClass="iconClass"
98
98
  :offset="menuOffset"
99
99
  ref="btn-icon"
100
- :size="size"
101
100
  :self="self"
101
+ :size="size"
102
102
  :tooltip="tooltip"
103
103
  @onClick="handleClick"
104
104
  >
105
105
  <template v-slot:menu>
106
- <slot name='menu' />
106
+ <slot name="menu" />
107
107
  </template>
108
108
  </UBtnIcon>
109
109
 
@@ -112,13 +112,14 @@ const toLowerCase = (str) => str.toLowerCase()
112
112
  v-if="states === 'Button'"
113
113
  class="u-mb-btn"
114
114
  :color="color"
115
- :left-icon="iconClass"
115
+ :dataTestId="dataTestId"
116
116
  :label="label"
117
+ :left-icon="iconClass"
117
118
  outline
118
119
  :size="size"
119
120
  >
120
121
  <template v-slot:menu>
121
- <slot name='menu' />
122
+ <slot name="menu" />
122
123
  </template>
123
124
  </UBtnStd>
124
125
 
@@ -128,29 +129,30 @@ const toLowerCase = (str) => str.toLowerCase()
128
129
  :class="`u-mb-avatar size-${size}`"
129
130
  :color="color"
130
131
  content-class="u-options-menu"
131
- no-caps
132
+ :dataTestId="dataTestId"
132
133
  :menu-offset="menuOffset"
134
+ no-caps
133
135
  rounded
134
136
  text-color="black"
135
137
  unelevated
136
138
  >
137
139
  <template #label>
138
140
  <q-item class="account-drop-down">
139
- <q-item-section avatar class="q-pr-xs">
141
+ <q-item-section class="q-pr-xs" avatar>
140
142
  <UAvatar
141
143
  v-if="avatarUrl"
142
144
  :image="avatarUrl"
143
145
  :name="displayName"
144
- size="md"
145
- :showIndicator="false"
146
146
  :round="true"
147
+ :showIndicator="false"
148
+ size="md"
147
149
  />
148
150
  <UAvatar
149
151
  v-else
150
152
  :name="displayName"
151
- size="md"
152
- :showIndicator="false"
153
153
  :round="true"
154
+ :showIndicator="false"
155
+ size="md"
154
156
  />
155
157
  </q-item-section>
156
158
  <q-item-section v-if="displayName">
@@ -160,20 +162,19 @@ const toLowerCase = (str) => str.toLowerCase()
160
162
  </q-item-section>
161
163
  </q-item>
162
164
  </template>
163
- <slot name='menu' />
165
+ <slot name="menu" />
164
166
  </q-btn-dropdown>
165
167
 
166
-
167
168
  <!-- 5. Menu button Prefix state -->
168
169
  <q-btn-dropdown
169
170
  v-if="states === 'Prefix'"
170
- class="u-prefix-dropdown text-body-sm"
171
- :class="`btn-field-${size}`"
171
+ :class="`u-prefix-dropdown text-body-sm btn-field-${size}`"
172
172
  content-class="u-prefix-dropdown-list"
173
+ :dataTestId="dataTestId"
173
174
  flat
174
175
  menu-anchor="top right"
175
- menu-self="bottom middle"
176
176
  :menu-offset="menuOffset"
177
+ menu-self="bottom middle"
177
178
  rounded
178
179
  >
179
180
  <template #label>
@@ -184,7 +185,7 @@ const toLowerCase = (str) => str.toLowerCase()
184
185
  />
185
186
  <label class="selected-code"> {{ selectedCountry.code }}</label>
186
187
  </template>
187
- <slot name='menu' />
188
+ <slot name="menu" />
188
189
  </q-btn-dropdown>
189
190
  </template>
190
191
 
@@ -5,6 +5,10 @@ const props = defineProps({
5
5
  data: {
6
6
  type: Array,
7
7
  },
8
+ dataTestId: {
9
+ type: String,
10
+ default: 'menu-dropdown',
11
+ },
8
12
  iconClass: {
9
13
  type: String,
10
14
  },
@@ -23,7 +27,10 @@ const props = defineProps({
23
27
  </script>
24
28
 
25
29
  <template>
26
- <q-list :class="`u-menu-dropdown size-${size} ${menuClass} q-gutter-y-xxs`">
30
+ <q-list
31
+ :class="`u-menu-dropdown size-${size} ${menuClass} q-gutter-y-xxs`"
32
+ :dataTestId="dataTestId"
33
+ >
27
34
  <template v-for="(item, index) in data" :key="index">
28
35
  <UMenuItem
29
36
  :iconClass="iconClass"
@@ -1,7 +1,22 @@
1
1
  <script setup>
2
2
  import UBadgeStd from './UBadgeStd.vue'
3
3
 
4
+ const emit = defineEmits(['onTabClick'])
5
+
6
+ const selectedTab = defineModel('selectedTab', {
7
+ type: [String, Number],
8
+ default: null,
9
+ })
10
+
4
11
  const props = defineProps({
12
+ buttonTabsOptions: {
13
+ type: Array,
14
+ default: () => [],
15
+ },
16
+ dataTestId: {
17
+ type: String,
18
+ default: 'tab-btn-std',
19
+ },
5
20
  size: {
6
21
  type: String,
7
22
  default: 'md',
@@ -10,19 +25,8 @@ const props = defineProps({
10
25
  type: Boolean,
11
26
  default: false,
12
27
  },
13
- buttonTabsOptions: {
14
- type: Array,
15
- default: () => [],
16
- },
17
28
  })
18
29
 
19
- const selectedTab = defineModel('selectedTab', {
20
- type: [String, Number],
21
- default: null,
22
- })
23
-
24
- const emit = defineEmits(['onTabClick'])
25
-
26
30
  const handleTabClick = (value) => {
27
31
  emit('onTabClick', value)
28
32
  }
@@ -30,13 +34,14 @@ const handleTabClick = (value) => {
30
34
 
31
35
  <template>
32
36
  <q-tabs
37
+ :active-class="`u-tab-active ${standard ? 'tab-standard' : ''}`"
38
+ class="u-tabs-outer"
39
+ :dataTestId="dataTestId"
33
40
  dense
34
41
  indicator-color="transparent"
35
42
  inline-label
36
43
  :model-value="selectedTab"
37
44
  no-caps
38
- class="u-tabs-outer"
39
- :active-class="`u-tab-active ${standard ? 'tab-standard' : ''}`"
40
45
  >
41
46
  <template v-for="(tabOption, key) in buttonTabsOptions" :key="tabOption.id">
42
47
  <q-tab
@@ -44,28 +49,28 @@ const handleTabClick = (value) => {
44
49
  :class="`u-tab-button text-caption-${size} u-tab-${size} ${
45
50
  key !== buttonTabsOptions.length - 1 ? 'q-mr-xs' : ''
46
51
  }`"
47
- :ripple="false"
52
+ :aria-label="tabOption.label"
48
53
  :disable="tabOption.disable"
49
54
  :name="tabOption.id"
50
- :aria-label="tabOption.label"
55
+ :ripple="false"
51
56
  @click="handleTabClick(tabOption.id)"
52
57
  >
53
58
  <template v-slot:default>
54
59
  <q-icon
55
60
  v-if="tabOption.icon"
56
61
  :class="tabOption.icon"
57
- :aria-label="tabOption.label"
58
62
  :alt="tabOption.label"
63
+ :aria-label="tabOption.label"
59
64
  />
60
65
  <p class="u-tab-label truncated-label left-icon-label">
61
66
  {{ tabOption.label ? tabOption.label : '' }}
62
67
  </p>
63
68
  <UBadgeStd
64
69
  v-if="tabOption.badgeLabel"
65
- :label="tabOption.badgeLabel"
70
+ :class="`q-ml-xs ${size === 'sm' ? 'badge-small' : ''}`"
66
71
  color="primary"
72
+ :label="tabOption.badgeLabel"
67
73
  :size="size === 'md' ? 'md' : ''"
68
- :class="`q-ml-xs ${size === 'sm' ? 'badge-small' : ''}`"
69
74
  />
70
75
  </template>
71
76
  </q-tab>
@@ -74,10 +79,10 @@ const handleTabClick = (value) => {
74
79
  :class="`u-tab-button text-caption-${size} u-tab-${size} ${
75
80
  key !== buttonTabsOptions.length - 1 ? 'q-mr-xs' : ''
76
81
  }`"
77
- :ripple="false"
78
- :name="tabOption.id"
79
82
  :aria-label="tabOption.label"
80
83
  :disable="tabOption.disable"
84
+ :name="tabOption.id"
85
+ :ripple="false"
81
86
  @click="handleTabClick(tabOption.id)"
82
87
  >
83
88
  <template v-slot:default>
@@ -86,10 +91,10 @@ const handleTabClick = (value) => {
86
91
  </p>
87
92
  <UBadgeStd
88
93
  v-if="tabOption.badgeLabel"
89
- :label="tabOption.badgeLabel"
94
+ :class="`q-ml-xs ${size === 'sm' ? 'badge-small' : ''}`"
90
95
  color="primary"
96
+ :label="tabOption.badgeLabel"
91
97
  :size="size === 'md' ? 'md' : ''"
92
- :class="`q-ml-xs ${size === 'sm' ? 'badge-small' : ''}`"
93
98
  />
94
99
  </template>
95
100
  </q-tab>
@@ -1,77 +1,82 @@
1
1
  <script setup>
2
+ const selectedTab = defineModel({
3
+ required: true,
4
+ type: [Boolean, String, Number],
5
+ })
6
+
2
7
  const props = defineProps({
8
+ align: { type: String, default: 'justify' },
9
+ dataTestId: {
10
+ type: String,
11
+ default: 'tabs-std',
12
+ },
3
13
  tabs: {
4
14
  type: Array,
5
15
  required: true,
6
16
  },
7
- align: { type: String, default: 'justify' },
8
- })
9
-
10
- const selectedTab = defineModel({
11
- required: true,
12
- type: [Boolean, String, Number],
13
17
  })
14
18
  </script>
15
19
 
16
20
  <template>
17
21
  <q-tabs
18
22
  v-model="selectedTab"
19
- :dense="true"
23
+ class="u-tabs-std text-caption-md"
20
24
  active-color="primary"
25
+ :align="align"
26
+ :dataTestId="dataTestId"
27
+ :dense="true"
21
28
  indicator-color="primary"
22
- outside-arrows
23
29
  inline-label
24
30
  mobile-arrows
25
- :align="align"
26
31
  no-caps
27
- class="u-tabs-std text-caption-md"
32
+ outside-arrows
28
33
  >
29
34
  <template v-for="tab in tabs" :key="tab.name">
30
35
  <q-tab
31
- :aria-label="tab.label"
32
36
  v-if="!tab.route"
37
+ :aria-label="tab.label"
38
+ :disable="tab.disable"
33
39
  :name="tab.name"
34
40
  :ripple="false"
35
- :disable="tab.disable"
36
41
  >
37
42
  <template v-slot:default>
38
43
  <q-icon
39
- :aria-label="tab.label"
40
- :alt="tab.label"
41
44
  v-if="tab.leftIcon"
42
45
  :class="`left-icon ${tab.leftIcon}`"
46
+ :alt="tab.label"
47
+ :aria-label="tab.label"
43
48
  />
44
49
  <p class="q-ma-none">{{ tab.label }}</p>
45
50
  <q-icon
46
- :aria-label="tab.label"
47
- :alt="tab.label"
48
51
  v-if="tab.rightIcon"
49
52
  :class="`right-icon ${tab.rightIcon}`"
53
+ :alt="tab.label"
54
+ :aria-label="tab.label"
50
55
  />
51
56
  </template>
52
57
  </q-tab>
53
58
  <q-route-tab
54
59
  v-else
60
+ :aria-label="tab.label"
61
+ :disable="tab.disable"
62
+ exact
55
63
  :name="tab.name"
56
64
  :ripple="false"
57
65
  :to="`${tab.route}`"
58
- exact
59
- :aria-label="tab.label"
60
- :disable="tab.disable"
61
66
  >
62
67
  <template v-slot:default>
63
68
  <q-icon
64
- :aria-label="tab.label"
65
- :alt="tab.label"
66
69
  v-if="tab.leftIcon"
67
70
  :class="`left-icon ${tab.leftIcon}`"
71
+ :alt="tab.label"
72
+ :aria-label="tab.label"
68
73
  />
69
74
  <p class="q-ma-none">{{ tab.label }}</p>
70
75
  <q-icon
71
- :aria-label="tab.label"
72
- :alt="tab.label"
73
76
  v-if="tab.rightIcon"
74
77
  :class="`right-icon ${tab.rightIcon}`"
78
+ :alt="tab.label"
79
+ :aria-label="tab.label"
75
80
  />
76
81
  </template>
77
82
  </q-route-tab>
@@ -2,27 +2,31 @@
2
2
  import { onMounted, watch } from 'vue'
3
3
 
4
4
  const props = defineProps({
5
- name: {
5
+ checkedIcon: {
6
6
  type: String,
7
- default: 'toggle',
7
+ default: '',
8
+ },
9
+ dataTestId: {
10
+ type: String,
11
+ default: 'toggle-std',
8
12
  },
9
13
  disabled: {
10
14
  type: Boolean,
11
15
  default: false,
12
16
  },
13
- label: {
14
- type: String,
15
- default: '',
16
- },
17
17
  id: {
18
18
  type: [String, Number],
19
19
  default: 'u-toggle',
20
20
  required: true, // it is required for to match accessibility crieteria
21
21
  },
22
- checkedIcon: {
22
+ label: {
23
23
  type: String,
24
24
  default: '',
25
25
  },
26
+ name: {
27
+ type: String,
28
+ default: 'toggle',
29
+ },
26
30
  unCheckedIcon: {
27
31
  type: String,
28
32
  default: '',
@@ -82,27 +86,28 @@ watch(toggle, () => {
82
86
  <template>
83
87
  <label class="hidden" :for="`u-toggle-${id}`">{{ label }}</label>
84
88
  <q-toggle
85
- :id="`u-toggle-${id}`"
89
+ v-bind="$attrs"
86
90
  v-model="toggle"
87
- :name="name"
88
- color="primary"
89
91
  class="u-toggle"
92
+ color="primary"
93
+ :dataTestId="dataTestId"
90
94
  :disable="disabled"
91
- v-bind="$attrs"
95
+ :id="`u-toggle-${id}`"
96
+ :name="name"
92
97
  >
93
98
  <template v-slot:default>
94
99
  <q-icon
95
100
  v-if="checkedIcon && toggle"
96
- :id="`u-toggle-right-icon-${name}`"
97
101
  :class="`${checkedIcon} u-checked-icon`"
98
102
  :aria-label="`${name ? name : ''} checked toggle icon`"
103
+ :id="`u-toggle-right-icon-${name}`"
99
104
  >
100
105
  </q-icon>
101
106
  <q-icon
102
107
  v-if="unCheckedIcon && !toggle"
103
- :id="`u-toggle-left-icon-${name}`"
104
108
  :class="`${unCheckedIcon} u-unchecked-icon`"
105
109
  :aria-label="`${name ? name : ''} unchecked toggle icon`"
110
+ :id="`u-toggle-left-icon-${name}`"
106
111
  >
107
112
  </q-icon>
108
113
  </template>
@@ -1,23 +1,26 @@
1
1
  <script setup>
2
2
  import { computed } from 'vue'
3
3
  import UBtnIcon from './UBtnIcon.vue'
4
- import UBtnStd from './UBtnStd.vue';
5
-
4
+ import UBtnStd from './UBtnStd.vue'
6
5
 
7
6
  const emit = defineEmits(['navigateBack'])
8
7
  const props = defineProps({
8
+ dataTestId: {
9
+ type: String,
10
+ default: 'toolbar',
11
+ },
9
12
  isMiniState: {
10
13
  type: Boolean,
11
14
  required: true,
12
15
  },
13
- title: {
14
- type: String,
15
- required: true,
16
- },
17
16
  isSubPage: {
18
17
  type: Boolean,
19
18
  required: true,
20
19
  },
20
+ title: {
21
+ type: String,
22
+ required: true,
23
+ },
21
24
  })
22
25
 
23
26
  // Computed property for the title text
@@ -32,13 +35,14 @@ const handleClick = () => {
32
35
  </script>
33
36
 
34
37
  <template>
35
- <q-toolbar class="u-header-toolbar-container">
38
+ <q-toolbar class="u-header-toolbar-container" :dataTestId="dataTestId">
36
39
  <!-- Expand icon to open sidebar or drawer-->
37
40
  <UBtnIcon
38
41
  v-if="isMiniState"
42
+ class="q-ml-xxs"
39
43
  ariaLabel="Sidebar expand icon"
40
44
  color="primary"
41
- class="q-ml-xxs"
45
+ dataTestId="expand-button"
42
46
  iconClass="fa-kit-duotone fa-sidebar-shrink"
43
47
  size="md"
44
48
  />
@@ -46,26 +50,29 @@ const handleClick = () => {
46
50
  <section class="fit row justify-between items-center q-mx-ms">
47
51
  <!-- Title container with dynamic title and optional back button -->
48
52
  <UBtnStd
49
- v-if="isSubPage"
50
- :aria-label="pageTitle"
51
- class="back_to_button"
52
- color="primary"
53
- :flat="true"
54
- :label="pageTitle"
55
- left-icon="fa-kit-duotone fa-circle-arrow-left"
56
- @click="handleClick"
57
- />
58
- <span v-else class="q-my-none text-heading-sm">{{ pageTitle }}</span>
53
+ v-if="isSubPage"
54
+ class="back_to_button"
55
+ :aria-label="pageTitle"
56
+ color="primary"
57
+ dataTestId="back-button"
58
+ :flat="true"
59
+ :label="pageTitle"
60
+ left-icon="fa-kit-duotone fa-circle-arrow-left"
61
+ @click="handleClick"
62
+ />
63
+ <span v-else class="q-my-none text-heading-sm" dataTestId="toolbar-title">
64
+ {{ pageTitle }}
65
+ </span>
59
66
 
60
67
  <!-- Action element container -->
61
68
  <div class="u-header-toolbar-action-container">
62
- <slot name="right_section"/>
69
+ <slot name="right_section" />
63
70
  </div>
64
71
  </section>
65
72
  </q-toolbar>
66
73
  </template>
67
74
 
68
- <style lang="sass">
75
+ <style lang="sass">
69
76
  .u-header-toolbar-container
70
77
  background-color: white
71
78
  width: 100%
@@ -1,74 +1,79 @@
1
1
  <script setup>
2
2
  import { ref } from 'vue'
3
+ import { fixStringLength, formatDate, getFileCategory } from '../../utils/data'
3
4
  import UBtnIcon from './UBtnIcon.vue'
4
5
  import UBtnStd from './UBtnStd.vue'
5
6
  import UInputTextStd from './UInputTextStd.vue'
6
7
  import UTooltip from './UTooltip.vue'
7
- import { fixStringLength, formatDate, getFileCategory } from '../../utils/data'
8
+
9
+ const emit = defineEmits(['onUploadFactory', 'onViewFile', 'getFilesOnAdded'])
8
10
 
9
11
  const props = defineProps({
10
12
  autoUpload: {
11
13
  type: Boolean,
12
14
  default: true,
13
15
  },
14
- noThumbnails: {
15
- type: Boolean,
16
- default: true,
17
- },
18
- multiple: {
19
- type: Boolean,
20
- default: false,
21
- },
22
16
  batch: {
23
17
  type: Boolean,
24
18
  default: false,
25
19
  },
26
- fileUploadUrl: {
20
+ dataTestId: {
27
21
  type: String,
22
+ default: 'uploader',
28
23
  },
29
- size: {
30
- type: String,
31
- default: 'sm',
32
- },
33
- removeIconLabel: {
24
+ description: {
34
25
  type: String,
35
- default: 'Remove File',
26
+ default: 'Drag and drop your file or select choose file.',
36
27
  },
37
28
  editIconLabel: {
38
29
  type: String,
39
30
  default: 'Edit File Name',
40
31
  },
41
- viewIconLabel: {
32
+ fileIconColor: {
33
+ type: String,
34
+ default: 'primary',
35
+ },
36
+ fileNameLimit: {
37
+ type: Number,
38
+ default: 25,
39
+ },
40
+ fileUploadUrl: {
42
41
  type: String,
43
- default: 'view File Name',
44
42
  },
45
43
  listExternal: {
46
44
  type: Boolean,
47
45
  default: false,
48
46
  },
49
- selectFileBtnLabel: {
47
+ multiple: {
48
+ type: Boolean,
49
+ default: false,
50
+ },
51
+ noThumbnails: {
52
+ type: Boolean,
53
+ default: true,
54
+ },
55
+ removeIconLabel: {
50
56
  type: String,
51
- default: 'Choose File',
57
+ default: 'Remove File',
52
58
  },
53
- description: {
59
+ selectFileBtnLabel: {
54
60
  type: String,
55
- default: 'Drag and drop your file or select choose file.',
61
+ default: 'Choose File',
56
62
  },
57
63
  showUploadBtn: {
58
64
  type: Boolean,
59
65
  default: true,
60
66
  },
61
- fileNameLimit: {
62
- type: Number,
63
- default: 25,
67
+ size: {
68
+ type: String,
69
+ default: 'sm',
64
70
  },
65
- fileIconColor: {
71
+ viewIconLabel: {
66
72
  type: String,
67
- default: 'primary',
73
+ default: 'view File Name',
68
74
  },
69
75
  })
70
76
 
71
- const emit = defineEmits(['onUploadFactory', 'onViewFile', 'getFilesOnAdded'])
72
77
  const fileDisplayName = ref([])
73
78
  const isEditing = ref([])
74
79
  const uploaderRef = ref(null)
@@ -79,18 +84,12 @@ const cancelEdit = (payload) => {
79
84
  isEditing.value[index] = false
80
85
  }
81
86
 
82
- const handleViewClick = (file) => {
83
- return emit('onViewFile', file)
84
- }
85
-
86
87
  const editFileName = (index) => {
87
88
  isEditing.value[index] = true
88
89
  }
89
90
 
90
- const updateFileName = (payload) => {
91
- const { index, scope, file } = payload
92
- scope.files[index].displayName = fileDisplayName.value[file['__key']]
93
- isEditing.value[index] = false
91
+ const handleViewClick = (file) => {
92
+ return emit('onViewFile', file)
94
93
  }
95
94
 
96
95
  const OnFileAdded = (files) => {
@@ -114,6 +113,12 @@ const removeFile = (payload) => {
114
113
  scope.removeFile(file)
115
114
  }
116
115
 
116
+ const updateFileName = (payload) => {
117
+ const { index, scope, file } = payload
118
+ scope.files[index].displayName = fileDisplayName.value[file['__key']]
119
+ isEditing.value[index] = false
120
+ }
121
+
117
122
  const upload = () => {
118
123
  uploaderRef.value.upload()
119
124
  }
@@ -125,12 +130,13 @@ defineExpose({ upload })
125
130
  <q-uploader
126
131
  v-bind="$attrs"
127
132
  class="u-uploader"
128
- label="Drag and drop your file or select choose file."
129
- ref="uploaderRef"
130
133
  :auto-upload="autoUpload"
131
134
  :batch="batch"
135
+ :dataTestId="dataTestId"
136
+ label="Drag and drop your file or select choose file."
132
137
  :multiple="multiple"
133
138
  :no-thumbnails="noThumbnails"
139
+ ref="uploaderRef"
134
140
  :url="fileUploadUrl"
135
141
  @added="OnFileAdded"
136
142
  @uploaded="OnFileUploaded"
@@ -138,8 +144,8 @@ defineExpose({ upload })
138
144
  <template v-slot:header="scope">
139
145
  <div v-if="scope.canAddFiles" class="q-py-md q-px-xl bg-neutral-2">
140
146
  <div class="text-center">
141
- <img src="../../assets/files.png" alt="Upload Files" />
142
- <div class="text-body-md">
147
+ <img alt="Upload Files" src="../../assets/files.png" />
148
+ <div class="text-body-md" dataTestId="description">
143
149
  {{ description }}
144
150
  </div>
145
151
  </div>
@@ -147,9 +153,10 @@ defineExpose({ upload })
147
153
  <UBtnStd
148
154
  class="q-mt-md q-mb-md"
149
155
  color="primary"
150
- size="lg"
156
+ dataTestId="select-file-btn"
151
157
  :full-width="true"
152
158
  :label="selectFileBtnLabel"
159
+ size="lg"
153
160
  @click="scope.pickFiles"
154
161
  >
155
162
  {{ selectFileBtnLabel }}
@@ -160,10 +167,11 @@ defineExpose({ upload })
160
167
  <UBtnStd
161
168
  v-if="scope.canUpload && showUploadBtn"
162
169
  class="q-mt-md q-mb-md"
163
- size="sm"
164
- icon="cloud_upload"
165
170
  color="primary"
171
+ dataTestId="upload-btn"
166
172
  flat
173
+ icon="cloud_upload"
174
+ size="sm"
167
175
  @click="scope.upload"
168
176
  >
169
177
  <UTooltip description="Upload Files" />
@@ -175,11 +183,14 @@ defineExpose({ upload })
175
183
  <div
176
184
  v-if="!listExternal && scope.files"
177
185
  class="list-container q-my-xxs"
186
+ dataTestId="file-list"
178
187
  >
179
188
  <q-card
180
189
  v-for="(file, index) in scope.files"
181
190
  :class="`uploader-list list-size-${size} ${
182
- file.__status == 'uploading' ? 'q-py-xs q-px-sm' : 'uploaded-container'
191
+ file.__status == 'uploading'
192
+ ? 'q-py-xs q-px-sm'
193
+ : 'uploaded-container'
183
194
  }`"
184
195
  :key="file.__key"
185
196
  >
@@ -220,9 +231,9 @@ defineExpose({ upload })
220
231
 
221
232
  <q-icon
222
233
  class="icon-close fa-kit-duotone fa-circle-xmark"
234
+ :aria-label="removeIconLabel"
223
235
  size="sm"
224
236
  tabindex="0"
225
- :aria-label="removeIconLabel"
226
237
  @click="removeFile({ scope, file, index })"
227
238
  />
228
239
  </div>
@@ -273,9 +284,9 @@ defineExpose({ upload })
273
284
 
274
285
  <q-icon
275
286
  class="icon-close fa-kit-duotone fa-circle-xmark"
287
+ :aria-label="removeIconLabel"
276
288
  size="sm"
277
289
  tabindex="0"
278
- :aria-label="removeIconLabel"
279
290
  @click="removeFile({ scope, file, index })"
280
291
  />
281
292
  </div>
@@ -328,9 +339,9 @@ defineExpose({ upload })
328
339
  <span class="text-caption-md title flex">
329
340
  <UTooltip
330
341
  anchor="center end"
331
- self="center end"
332
342
  :description="file.displayName || file.name"
333
343
  :offset="[4, 4]"
344
+ self="center end"
334
345
  />
335
346
 
336
347
  {{
@@ -346,39 +357,39 @@ defineExpose({ upload })
346
357
  </div>
347
358
 
348
359
  <UBtnIcon
360
+ v-if="!isEditing[index] && size == 'md'"
349
361
  iconClass="fa-kit-duotone fa-pen-to-square"
362
+ :aria-label="editIconLabel"
350
363
  color="primary"
351
364
  size="md"
352
365
  tabindex="0"
353
- :aria-label="editIconLabel"
354
366
  @click="editFileName(index)"
355
- v-if="!isEditing[index] && size == 'md'"
356
367
  />
357
368
 
358
369
  <UBtnIcon
359
370
  iconClass="fa-kit-duotone fa-trash-can"
371
+ :aria-label="removeIconLabel"
360
372
  color="accent"
361
373
  size="md"
362
374
  tabindex="0"
363
- :aria-label="removeIconLabel"
364
375
  @click="removeFile({ scope, file, index })"
365
376
  />
366
377
 
367
378
  <UBtnStd
379
+ v-if="size == 'md'"
380
+ :aria-label="viewIconLabel"
368
381
  color="primary"
369
382
  label="View"
370
- size="sm"
371
383
  outline
372
- :aria-label="viewIconLabel"
384
+ size="sm"
373
385
  @onClick="handleViewClick(file)"
374
- v-if="size == 'md'"
375
386
  />
376
387
  </div>
377
- <div class="q-my-ba" v-if="isEditing[index]">
388
+ <div v-if="isEditing[index]" class="q-my-ba">
378
389
  <UInputTextStd
390
+ v-model="fileDisplayName[file.__key]"
379
391
  label="Edit file name"
380
392
  size="md"
381
- v-model="fileDisplayName[file.__key]"
382
393
  />
383
394
  </div>
384
395
  <div
@@ -386,39 +397,39 @@ defineExpose({ upload })
386
397
  class="list-items edit-button row q-mt-ba"
387
398
  >
388
399
  <UBtnStd
400
+ :aria-label="editIconLabel"
389
401
  color="primary"
390
- label="Edit"
391
- size="md"
392
402
  flat
393
- :aria-label="editIconLabel"
394
403
  :full-width="true"
404
+ label="Edit"
405
+ size="md"
395
406
  @click="editFileName(index)"
396
407
  />
397
408
  <UBtnStd
409
+ :aria-label="viewIconLabel"
398
410
  color="primary"
399
- label="View File"
400
- size="md"
401
411
  :full-width="true"
412
+ label="View File"
402
413
  :outline="true"
403
- :aria-label="viewIconLabel"
414
+ size="md"
404
415
  @onClick="handleViewClick(file)"
405
416
  />
406
417
  </div>
407
418
  <div v-if="isEditing[index]" class="list-items update-button row">
408
419
  <UBtnStd
409
420
  color="primary"
410
- label="Cancel"
411
- size="md"
412
421
  flat
413
422
  :full-width="true"
423
+ label="Cancel"
424
+ size="md"
414
425
  @click="cancelEdit({ index, file })"
415
426
  />
416
427
 
417
428
  <UBtnStd
418
429
  color="primary"
430
+ :full-width="true"
419
431
  label="Update file name"
420
432
  size="md"
421
- :full-width="true"
422
433
  @click="updateFileName({ scope, file, index })"
423
434
  />
424
435
  </div>