@usssa/component-library 1.0.0-beta.9 → 1.0.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.
@@ -1,9 +1,9 @@
1
1
  <script setup>
2
- import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
2
+ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
3
3
  import UInputTextStd from './UInputTextStd.vue'
4
4
  import UTooltip from './UTooltip.vue'
5
5
 
6
- const emit = defineEmits(['onRightIconClick', 'onUpdate'])
6
+ const emit = defineEmits(['onRightIconClick', 'onUpdate', 'updateInputVal'])
7
7
  const modelValue = defineModel()
8
8
  defineOptions({
9
9
  inheritAttrs: false,
@@ -67,6 +67,10 @@ const props = defineProps({
67
67
  rightIconAriaLabel: {
68
68
  type: String,
69
69
  },
70
+ selectedAddress: {
71
+ type: String,
72
+ default: '',
73
+ },
70
74
  size: {
71
75
  type: String,
72
76
  default: 'md',
@@ -85,7 +89,13 @@ let sessionToken, autocompleteSuggestion
85
89
  const inputRef = ref(null)
86
90
  const menuWidth = ref(0)
87
91
  const predictions = ref([])
88
- const resultItem = ref({})
92
+ const resultItem = ref(
93
+ props.selectedAddress?.length
94
+ ? { displayName: props.selectedAddress }
95
+ : modelValue.value?.length
96
+ ? { displayName: modelValue.value }
97
+ : {}
98
+ )
89
99
  const resultsMenuRef = ref(null)
90
100
  const resultsMenuShowing = ref(false)
91
101
 
@@ -96,10 +106,6 @@ const leftBorderRadius = computed(() => {
96
106
  return ''
97
107
  })
98
108
 
99
- const handleClear = () => {
100
- modelValue.value = ''
101
- }
102
-
103
109
  const handleUpdate = async (input) => {
104
110
  // fetchAutocompleteSuggestions reference
105
111
  // https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest
@@ -220,6 +226,21 @@ const parseAddressComponents = (addressComponents) => {
220
226
  return address
221
227
  }
222
228
 
229
+ const updateInputVal = (val) => {
230
+ if (!val?.length) {
231
+ modelValue.value = ''
232
+ resultItem.value = {}
233
+ }
234
+ if (val?.length === 1) {
235
+ resultItem.value = {}
236
+ modelValue.value = val
237
+ nextTick(() => {
238
+ inputRef.value?.focus()
239
+ })
240
+ }
241
+ emit('updateInputVal', val)
242
+ }
243
+
223
244
  const updateMenuWidth = () => {
224
245
  const el =
225
246
  inputRef.value?.$el.querySelector('.q-field__control') ||
@@ -240,6 +261,16 @@ watch(modelValue, async (value) => {
240
261
  emit('onUpdate', {})
241
262
  }
242
263
  })
264
+
265
+ watch(
266
+ () => resultItem.value?.formattedAddress,
267
+ (value) => {
268
+ if (!value)
269
+ nextTick(() => {
270
+ inputRef.value?.focus()
271
+ })
272
+ }
273
+ )
243
274
  </script>
244
275
 
245
276
  <template>
@@ -296,6 +327,7 @@ watch(modelValue, async (value) => {
296
327
  :standout="!outlined"
297
328
  type="text"
298
329
  @focus="onMenuShow"
330
+ @update:modelValue="updateInputVal($event)"
299
331
  >
300
332
  <!-- The 'fit' prop is used to ensure the menu matches the anchor's width for correct positioning,
301
333
  while the manual width styling enforces a specific width for visual consistency. -->
@@ -388,13 +420,11 @@ watch(modelValue, async (value) => {
388
420
 
389
421
  <UInputTextStd
390
422
  v-if="JSON.stringify(resultItem) !== '{}'"
391
- v-model="resultItem.formattedAddress"
423
+ v-model="resultItem.displayName"
392
424
  :dataTestId="dataTestId"
393
425
  :label="label"
394
- readonly
395
- rightIcon="fa-kit-duotone fa-circle-xmark"
396
426
  :size="size"
397
- @onRightIconClick="handleClear"
427
+ @update:modelValue="updateInputVal($event)"
398
428
  />
399
429
  </template>
400
430
 
@@ -139,6 +139,11 @@ const toLowerCase = (str) => str?.toLowerCase()
139
139
  v-for="country in options"
140
140
  v-ripple
141
141
  class="q-my-xxs"
142
+ :class="{
143
+ 'selected-item':
144
+ selectedCountry?.code === country?.code &&
145
+ selectedCountry?.label === country?.label,
146
+ }"
142
147
  clickable
143
148
  :key="country?.code"
144
149
  @click="selectCountry(country)"
@@ -165,8 +170,10 @@ const toLowerCase = (str) => str?.toLowerCase()
165
170
 
166
171
  <style lang="sass">
167
172
  .selected-code
168
- width: 1.5rem
173
+ width: auto
169
174
  color: $dark
175
+ .selected-item
176
+ background-color: $blue-1
170
177
  .u-dropdown-list
171
178
  .q-item__section--main
172
179
  margin-left: 0px
@@ -19,6 +19,10 @@ defineOptions({
19
19
  inheritAttrs: false,
20
20
  })
21
21
  const props = defineProps({
22
+ autocomplete: {
23
+ type: String,
24
+ default: 'on',
25
+ },
22
26
  borderless: {
23
27
  type: Boolean,
24
28
  default: false,
@@ -146,6 +150,7 @@ const handleRightIconClick = () => {
146
150
  v-model="modelValue"
147
151
  :class="`u-input field-${size} ${leftBorderRadius}`"
148
152
  :aria-describedby="hintText"
153
+ :autocomplete="autocomplete"
149
154
  :borderless="borderless"
150
155
  :bottom-slots="!!hintText"
151
156
  :disable="disable"
@@ -0,0 +1,404 @@
1
+ <script setup>
2
+ import { ref, onMounted, onUnmounted } from 'vue'
3
+ import UBtnStd from './UBtnStd.vue'
4
+ import UChip from './UChip.vue'
5
+ import UExpansionStd from './UExpansionStd.vue'
6
+ import UModal from './UModal.vue'
7
+ import UTabsStd from './UTabsStd.vue'
8
+ import { useScreenType } from '../../composables/useScreenType'
9
+
10
+ const model = defineModel('showMatchup')
11
+
12
+ const props = defineProps({
13
+ closeActionLabel: {
14
+ type: String,
15
+ default: 'Close',
16
+ },
17
+ closeIconLabel: {
18
+ type: String,
19
+ default: 'Close',
20
+ },
21
+ collapsedAriaLabel: {
22
+ type: String,
23
+ default: 'Collapsed',
24
+ },
25
+ expandAriaLabel: {
26
+ type: String,
27
+ default: 'Expanded',
28
+ },
29
+ gameDetails: {
30
+ type: Object,
31
+ required: true,
32
+ },
33
+ gameInformationLabel: {
34
+ type: String,
35
+ default: 'Game Information',
36
+ },
37
+ heading: {
38
+ type: String,
39
+ default: 'Game Detail',
40
+ },
41
+ matchupFields: {
42
+ type: Array,
43
+ required: true,
44
+ },
45
+ matchupTabLabel: {
46
+ type: String,
47
+ default: 'Previous Matchups',
48
+ },
49
+ reportTabLabel: {
50
+ type: String,
51
+ default: 'Pitching Report',
52
+ },
53
+ statTabLabel: {
54
+ type: String,
55
+ default: 'Team Stats',
56
+ },
57
+ teamOneDetails: {
58
+ type: Object,
59
+ required: true,
60
+ },
61
+ teamTwoDetails: {
62
+ type: Object,
63
+ required: true,
64
+ },
65
+ })
66
+
67
+ const $screen = useScreenType()
68
+
69
+ const currentTab = ref('stats')
70
+ const dateChip = ref(true)
71
+ const isSmallTab = ref(false)
72
+
73
+ const tabs = ref([
74
+ {
75
+ name: 'stats',
76
+ label: props.statTabLabel,
77
+ },
78
+ {
79
+ name: 'matchup',
80
+ label: props.matchupTabLabel,
81
+ },
82
+ {
83
+ name: 'report',
84
+ label: props.reportTabLabel,
85
+ },
86
+ ])
87
+
88
+ const closeModel = () => {
89
+ model.value = false
90
+ }
91
+
92
+ onMounted(() => {
93
+ const handleResize = () => {
94
+ isSmallTab.value = window.innerWidth < 900
95
+ }
96
+ handleResize()
97
+ window.addEventListener('resize', handleResize)
98
+ onUnmounted(() => {
99
+ window.removeEventListener('resize', handleResize)
100
+ })
101
+ })
102
+ </script>
103
+
104
+ <template>
105
+ <UModal
106
+ v-model="model"
107
+ class="u-matchup-model"
108
+ closeIcon="fa-kit-duotone fa-circle-xmark"
109
+ :closeIconLabel="closeIconLabel"
110
+ customSize="90%"
111
+ dataTestId="view matchup"
112
+ :heading="heading"
113
+ position="standard"
114
+ :show-action-buttons="true"
115
+ :show-secondary-buttons="true"
116
+ :size="$screen.isDesktop ? 'custom' : 'half'"
117
+ >
118
+ <template #content>
119
+ <template v-if="!$screen.isMobile">
120
+ <div class="matchup-field-container q-mb-ms flex column">
121
+ <div
122
+ class="matchup-fields flex items-start content-start self-stretch flex-wrap"
123
+ >
124
+ <div
125
+ v-for="field in matchupFields"
126
+ class="game-item flex column flex-start no-wrap"
127
+ :key="field.label"
128
+ >
129
+ <span class="text-description text-caption-sm">
130
+ {{ field.label }}
131
+ </span>
132
+ <span class="text-dark text-body-sm">{{ field.value }}</span>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ <div
137
+ :class="`team-card-container flex items-center self-stretch no-wrap q-mb-ms ${
138
+ isSmallTab ? 'column' : ''
139
+ }`"
140
+ >
141
+ <div class="team-card flex items-center self-stretch column no-wrap">
142
+ <div class="team-logo">
143
+ <img
144
+ :alt="teamOneDetails.name"
145
+ :src="teamOneDetails.logoUrl"
146
+ style="width: 80px; height: 80px"
147
+ />
148
+ </div>
149
+ <span class="text-caption-md text-dark text-center">
150
+ {{ teamOneDetails.name }}
151
+ </span>
152
+ <span class="text-caption-md text-description text-center">
153
+ MVP: {{ teamOneDetails.mvp }}
154
+ </span>
155
+ </div>
156
+ <div class="game-stats-card flex items-center column no-wrap">
157
+ <UChip
158
+ v-model="dateChip"
159
+ class="u-table-chip"
160
+ avatarLabel=""
161
+ :chipLabel="gameDetails.date"
162
+ :removable="false"
163
+ type="primary"
164
+ />
165
+ <div class="score-card flex content-center items-center no-wrap">
166
+ <div class="score text-heading-xxl text-positive">
167
+ {{ teamOneDetails.score }}
168
+ </div>
169
+ <div class="text-heading-xxl text-dark">-</div>
170
+ <div class="score text-heading-xxl text-dark">
171
+ {{ teamTwoDetails.score }}
172
+ </div>
173
+ </div>
174
+ <span class="text-heading-sm text-positive">
175
+ {{ gameDetails.gameType }}
176
+ </span>
177
+ </div>
178
+ <div class="team-card flex items-center self-stretch column no-wrap">
179
+ <div class="team-logo">
180
+ <img
181
+ :alt="teamOneDetails.name"
182
+ :src="teamTwoDetails.logoUrl"
183
+ style="width: 80px; height: 80px"
184
+ />
185
+ </div>
186
+ <span class="text-caption-md text-dark text-center">
187
+ {{ teamTwoDetails.name }}
188
+ </span>
189
+ <span class="text-caption-md text-description text-center">
190
+ MVP: {{ teamTwoDetails.mvp }}
191
+ </span>
192
+ </div>
193
+ </div>
194
+ <div>
195
+ <UTabsStd
196
+ v-model="currentTab"
197
+ class="q-mb-ba"
198
+ align="left"
199
+ data-test-id="matchup-section-tabs"
200
+ :tabs="tabs"
201
+ />
202
+ <q-tab-panels
203
+ v-model="currentTab"
204
+ class="bg-transparent"
205
+ animated
206
+ keep-alive
207
+ >
208
+ <q-tab-panel class="q-pa-none" name="stats">
209
+ <slot name="stats"></slot>
210
+ </q-tab-panel>
211
+ <q-tab-panel class="q-pa-none" name="matchup">
212
+ <slot name="matchup"></slot>
213
+ </q-tab-panel>
214
+ <q-tab-panel class="q-pa-none" name="report">
215
+ <slot name="report"></slot>
216
+ </q-tab-panel>
217
+ </q-tab-panels>
218
+ </div>
219
+ </template>
220
+ <template v-else>
221
+ <UExpansionStd
222
+ :collapsed-aria-label="collapsedAriaLabel"
223
+ dataTestId="game-information-expansion"
224
+ :disabled="disabled"
225
+ :enable-selection="false"
226
+ :expand-aria-label="expandAriaLabel"
227
+ expansion-icon="fa-kit fa-caret-down"
228
+ :expansion-icon-color="expansionIconColor"
229
+ :label="gameInformationLabel"
230
+ :row-card-height="8"
231
+ :toggle-icon-left="false"
232
+ >
233
+ <template #body>
234
+ <div class="matchup-field-container-mobile flex column">
235
+ <div
236
+ class="matchup-fields flex items-start content-start self-stretch flex-wrap"
237
+ >
238
+ <div
239
+ v-for="field in matchupFields"
240
+ class="game-item flex column flex-start no-wrap"
241
+ :key="field.label"
242
+ >
243
+ <span class="text-description text-caption-sm">
244
+ {{ field.label }}
245
+ </span>
246
+ <span class="text-dark text-body-sm">
247
+ {{ field.value }}
248
+ </span>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </template>
253
+ </UExpansionStd>
254
+ <q-separator class="q-my-ba" />
255
+ <div
256
+ class="flex column content-stretch items-start self-stretch team-container-mobile"
257
+ >
258
+ <UChip
259
+ v-model="dateChip"
260
+ class="u-table-chip"
261
+ avatarLabel=""
262
+ :chipLabel="gameDetails.date"
263
+ dense
264
+ :removable="false"
265
+ type="primary"
266
+ />
267
+
268
+ <div class="flex items-center self-stretch team-card-mobile no-wrap">
269
+ <div class="team-logo team-logo-mobile">
270
+ <img :alt="teamOneDetails.name" :src="teamOneDetails.logoUrl" />
271
+ </div>
272
+ <div class="flex column items-start team-detail-mobile">
273
+ <span class="text-caption-md text-dark text-start">
274
+ {{ teamOneDetails.name }}
275
+ </span>
276
+ <span class="text-body-xxs text-description text-start">
277
+ MVP: {{ teamOneDetails.mvp }}
278
+ </span>
279
+ </div>
280
+ <div
281
+ class="text-heading-xxs q-py-xs q-px-ba bg-neutral-3 team-score-mobile text-positive"
282
+ >
283
+ {{ teamOneDetails.score }}
284
+ </div>
285
+ </div>
286
+
287
+ <span class="text-heading-xxs text-positive q-py-ba text-center self-center">
288
+ {{ gameDetails.gameType }}
289
+ </span>
290
+
291
+ <div class="flex items-center self-stretch team-card-mobile no-wrap">
292
+ <div class="team-logo team-logo-mobile">
293
+ <img :alt="teamTwoDetails.name" :src="teamTwoDetails.logoUrl" />
294
+ </div>
295
+ <div class="flex column items-start team-detail-mobile">
296
+ <span class="text-caption-md text-dark text-start">
297
+ {{ teamTwoDetails.name }}
298
+ </span>
299
+ <span class="text-body-xxs text-description text-start">
300
+ MVP: {{ teamTwoDetails.mvp }}
301
+ </span>
302
+ </div>
303
+ <div
304
+ class="text-heading-xxs q-py-xs q-px-ba bg-neutral-3 team-score-mobile text-dark"
305
+ >
306
+ {{ teamTwoDetails.score }}
307
+ </div>
308
+ </div>
309
+ </div>
310
+ <q-separator class="q-my-ba" />
311
+
312
+ <div>
313
+ <UTabsStd
314
+ v-model="currentTab"
315
+ class="q-mb-ba"
316
+ align="left"
317
+ data-test-id="matchup-section-tabs"
318
+ :tabs="tabs"
319
+ />
320
+ <q-tab-panels
321
+ v-model="currentTab"
322
+ class="bg-transparent"
323
+ animated
324
+ keep-alive
325
+ >
326
+ <q-tab-panel class="q-pa-none" name="stats">
327
+ <slot name="stats"></slot>
328
+ </q-tab-panel>
329
+ <q-tab-panel class="q-pa-none" name="matchup">
330
+ <slot name="matchup"></slot>
331
+ </q-tab-panel>
332
+ <q-tab-panel class="q-pa-none" name="report">
333
+ <slot name="report"></slot>
334
+ </q-tab-panel>
335
+ </q-tab-panels>
336
+ </div>
337
+ </template>
338
+ </template>
339
+
340
+ <template #action_primary_two>
341
+ <UBtnStd
342
+ color="primary"
343
+ :label="closeActionLabel"
344
+ size="md"
345
+ @onClick="closeModel()"
346
+ />
347
+ </template>
348
+ </UModal>
349
+ </template>
350
+
351
+ <style lang="sass">
352
+ .u-matchup-model
353
+ .q-expansion-item__content > :nth-child(2)
354
+ padding: 0
355
+ .matchup-fields
356
+ gap: $ba
357
+ .matchup-field-container
358
+ padding: $ba $ba
359
+ background-color: $neutral-2
360
+ border: 1px solid $neutral-4
361
+ border-radius: $xxs
362
+ .matchup-field-container-mobile
363
+ border-radius: $xxs
364
+ .game-item
365
+ min-width: 8.562rem
366
+ flex: 1 0 0
367
+ .team-card-container
368
+ gap: $ms
369
+ .team-card
370
+ flex: 1 0 0
371
+ word-break: break-word
372
+ padding: $ms $ba
373
+ gap: $ba
374
+ background-color: $neutral-2
375
+ border-radius: $xs
376
+ .team-logo img
377
+ border-radius: $sm
378
+ .game-stats-card
379
+ width: 17.625rem
380
+ gap: 1.25rem
381
+ .score-card
382
+ gap: $ba
383
+ .score
384
+ width: 3.85rem
385
+ text-align: center
386
+ background-color: $neutral-3
387
+ padding: $xs $ba
388
+ border-radius: $xs
389
+
390
+ .team-score-mobile
391
+ border-radius: $xs
392
+ .team-card-mobile
393
+ gap: $xs
394
+ .team-detail-mobile
395
+ flex: 1 0 0
396
+ .team-logo-mobile
397
+ width: $lg
398
+ height: $lg
399
+ img
400
+ width: $lg
401
+ height: $lg
402
+ .team-container-mobile
403
+ gap: $ba
404
+ </style>
@@ -170,14 +170,13 @@ const handleClick = () => {
170
170
  {{ caption }}
171
171
  </q-item-label>
172
172
  </q-item-section>
173
- <q-item-section
173
+ <q-item-label
174
174
  v-else
175
- :class="`${labelColor} ${labelStyle} label`"
175
+ :class="`${labelColor} ${labelStyle}`"
176
176
  :tabindex="!inSheet ? '-1' : '0'"
177
177
  >
178
178
  {{ label }}
179
- <q-item-label></q-item-label>
180
- </q-item-section>
179
+ </q-item-label>
181
180
 
182
181
  <q-item-section v-if="rightIcon" side>
183
182
  <q-icon
@@ -224,6 +223,4 @@ const handleClick = () => {
224
223
  width: 100%
225
224
  height: 100%
226
225
  pointer-events: none
227
- .label
228
- word-break: break-all
229
226
  </style>
@@ -42,10 +42,18 @@ const props = defineProps({
42
42
  type: String,
43
43
  default: '',
44
44
  },
45
+ closeDialog: {
46
+ type: Boolean,
47
+ default: true,
48
+ },
45
49
  color: {
46
50
  type: String,
47
51
  default: 'neutral-7',
48
52
  },
53
+ customSheetHeight: {
54
+ type: Number,
55
+ default: 350,
56
+ },
49
57
  dataTestId: {
50
58
  type: String,
51
59
  default: 'multi-select',
@@ -182,7 +190,7 @@ const handleClick = (event) => {
182
190
  dialogs.value = [
183
191
  {
184
192
  open: true,
185
- height: 350,
193
+ height: props.customSheetHeight,
186
194
  persistent: true,
187
195
  transitionDuration: 500,
188
196
  position: 'bottom',
@@ -193,7 +201,9 @@ const handleClick = (event) => {
193
201
  }
194
202
 
195
203
  const handleClose = () => {
196
- dialogs.value[0].open = false
204
+ if (props.closeDialog) {
205
+ dialogs.value[0].open = false
206
+ }
197
207
  selectedItems.value = props.modelValue.length ? props.modelValue : []
198
208
  options.value = cloneOptions
199
209
  }
@@ -465,14 +475,14 @@ watch(selectedTab, () => {
465
475
  <q-icon :class="scope.opt.icon" color="neutral-13" size="1rem" />
466
476
  </div>
467
477
 
468
- <q-item-section>
478
+ <div>
469
479
  <q-item-label class="text-body-sm">
470
480
  {{ scope.opt.label }}
471
481
  </q-item-label>
472
482
  <q-item-label v-if="scope.opt.description" caption>
473
483
  {{ scope.opt.description }}
474
484
  </q-item-label>
475
- </q-item-section>
485
+ </div>
476
486
 
477
487
  <q-item-section v-if="scope.selected" side>
478
488
  <q-icon
@@ -611,6 +621,7 @@ watch(selectedTab, () => {
611
621
  min-height: $md
612
622
  align-items: center
613
623
  padding: 0px
624
+ gap: $xxs
614
625
 
615
626
  &.q-field--outlined .q-field__control
616
627
  border-radius: $xs
@@ -27,10 +27,18 @@ const props = defineProps({
27
27
  type: String,
28
28
  default: 'neutral-7',
29
29
  },
30
+ closeDialog: {
31
+ type: Boolean,
32
+ default: true,
33
+ },
30
34
  closeIconLabel: {
31
35
  type: String,
32
36
  default: 'Close Icon',
33
37
  },
38
+ customSheetHeight: {
39
+ type: Number,
40
+ default: 350,
41
+ },
34
42
  dataTestId: {
35
43
  type: String,
36
44
  default: 'select-std',
@@ -167,7 +175,7 @@ const handleClick = (event) => {
167
175
  dialogs.value = [
168
176
  {
169
177
  open: true,
170
- height: 350,
178
+ height: props.customSheetHeight,
171
179
  persistent: true,
172
180
  transitionDuration: 500,
173
181
  position: 'bottom',
@@ -184,7 +192,10 @@ const handleClick = (event) => {
184
192
 
185
193
  // sheet closing action
186
194
  const handleClose = () => {
187
- dialogs.value[0].open = false
195
+ if (props.closeDialog) {
196
+ dialogs.value[0].open = false
197
+ }
198
+
188
199
  if (model.value) {
189
200
  if (selectedItem.value) {
190
201
  if (model.value !== selectedItem.value) {
@@ -269,6 +280,14 @@ watch(
269
280
  }
270
281
  }
271
282
  )
283
+
284
+ watch(
285
+ () => props.options,
286
+ (newOptions) => {
287
+ initialOptions.value = [...newOptions]
288
+ },
289
+ { immediate: true }
290
+ )
272
291
  </script>
273
292
 
274
293
  <template>