@bildvitta/quasar-ui-asteroid 3.17.0-beta.9 → 3.17.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.
Files changed (58) hide show
  1. package/package.json +3 -2
  2. package/src/assets/sounds/nave-notification.mp3 +0 -0
  3. package/src/components/app-menu/QasAppMenu.vue +73 -15
  4. package/src/components/app-menu/QasAppMenu.yml +5 -5
  5. package/src/components/app-user/QasAppUser.vue +49 -40
  6. package/src/components/avatar/QasAvatar.vue +7 -8
  7. package/src/components/badge/QasBadge.vue +3 -29
  8. package/src/components/board-generator/QasBoardGenerator.vue +442 -40
  9. package/src/components/board-generator/QasBoardGenerator.yml +107 -12
  10. package/src/components/card/QasCard.vue +13 -4
  11. package/src/components/chart-view/QasChartView.vue +56 -3
  12. package/src/components/chart-view/QasChartView.yml +6 -0
  13. package/src/components/checkbox/QasCheckbox.vue +67 -11
  14. package/src/components/checkbox/QasCheckbox.yml +18 -0
  15. package/src/components/copy/QasCopy.vue +12 -2
  16. package/src/components/copy/QasCopy.yml +8 -0
  17. package/src/components/expansion-item/QasExpansionItem.vue +108 -76
  18. package/src/components/expansion-item/QasExpansionItem.yml +38 -10
  19. package/src/components/field/QasField.vue +1 -1
  20. package/src/components/form-generator/QasFormGenerator.vue +23 -10
  21. package/src/components/form-generator/QasFormGenerator.yml +2 -2
  22. package/src/components/grabbable/QasGrabbable.vue +14 -6
  23. package/src/components/grabbable/QasGrabbable.yml +4 -0
  24. package/src/components/grid-generator/QasGridGenerator.vue +3 -3
  25. package/src/components/grid-generator/QasGridGenerator.yml +2 -2
  26. package/src/components/grid-item/QasGridItem.vue +1 -1
  27. package/src/components/header/QasHeader.vue +11 -9
  28. package/src/components/infinite-scroll/QasInfiniteScroll.vue +16 -17
  29. package/src/components/infinite-scroll/QasInfiniteScroll.yml +7 -0
  30. package/src/components/list-view/QasListView.vue +16 -2
  31. package/src/components/list-view/QasListView.yml +9 -0
  32. package/src/components/radio/QasRadio.vue +24 -5
  33. package/src/components/radio/QasRadio.yml +6 -0
  34. package/src/components/select/QasSelect.vue +11 -2
  35. package/src/components/select/QasSelect.yml +1 -1
  36. package/src/components/select-filter/QasSelectFilter.vue +65 -0
  37. package/src/components/select-filter/QasSelectFilter.yml +36 -0
  38. package/src/components/stepper/QasStepper.vue +50 -3
  39. package/src/components/stepper-form-view/QasStepperFormView.vue +6 -4
  40. package/src/components/stepper-form-view/QasStepperFormView.yml +1 -1
  41. package/src/components/table-generator/QasTableGenerator.vue +3 -0
  42. package/src/components/text-truncate/QasTextTruncate.vue +77 -14
  43. package/src/components/text-truncate/QasTextTruncate.yml +14 -3
  44. package/src/components/uploader/QasUploader.vue +70 -24
  45. package/src/components/uploader/QasUploader.yml +15 -1
  46. package/src/components/welcome/QasWelcome.vue +8 -0
  47. package/src/components/welcome/QasWelcome.yml +3 -0
  48. package/src/composables/index.js +3 -1
  49. package/src/composables/private/index.js +1 -0
  50. package/src/composables/private/use-auth-user.js +20 -0
  51. package/src/composables/private/use-generator.js +20 -5
  52. package/src/composables/use-default-filters.js +106 -0
  53. package/src/composables/use-notifications.js +14 -0
  54. package/src/composables/use-query-cache.js +1 -1
  55. package/src/helpers/set-scroll-on-grab.js +9 -1
  56. package/src/shared/badge-config.js +29 -0
  57. package/src/vue-plugin.js +3 -0
  58. package/src/components/app-menu/private/PvAppMenuHelpChat.vue +0 -222
@@ -33,6 +33,11 @@ const props = defineProps({
33
33
  default: () => []
34
34
  },
35
35
 
36
+ fields: {
37
+ type: Object,
38
+ default: () => ({})
39
+ },
40
+
36
41
  limitPerPage: {
37
42
  type: Number,
38
43
  default: 12
@@ -62,7 +67,10 @@ const props = defineProps({
62
67
 
63
68
  defineExpose({ refresh, remove })
64
69
 
65
- const emit = defineEmits(['update:list', 'fetch-success', 'fetch-error'])
70
+ const emit = defineEmits(['fetch-success', 'fetch-error'])
71
+
72
+ const modelList = defineModel('list', { type: Array, default: () => [] })
73
+ const modelFields = defineModel('fields', { type: Object, default: () => ({}) })
66
74
 
67
75
  const axios = inject('axios')
68
76
 
@@ -74,7 +82,7 @@ const hasMadeFirstFetch = ref(false)
74
82
  const count = ref(0)
75
83
  const offset = ref(0)
76
84
 
77
- const listLength = computed(() => model.value.length)
85
+ const listLength = computed(() => modelList.value.length)
78
86
 
79
87
  const attributes = computed(() => ({
80
88
  offset: 100,
@@ -91,16 +99,6 @@ const containerStyle = computed(() => ({
91
99
  ...(props.maxHeight && { maxHeight: props.maxHeight, overflow: 'auto' })
92
100
  }))
93
101
 
94
- const model = computed({
95
- get () {
96
- return props.list
97
- },
98
-
99
- set (newList) {
100
- emit('update:list', newList)
101
- }
102
- })
103
-
104
102
  async function onLoad (_, done) {
105
103
  const hasMadeFirstFetchAndHasNoData = hasMadeFirstFetch.value && !listLength.value
106
104
  const hasFetchAllData = listLength.value && listLength.value >= count.value
@@ -124,11 +122,12 @@ async function fetchList () {
124
122
  params: { offset: offset.value, limit: props.limitPerPage, ...props.params }
125
123
  })
126
124
 
127
- const newList = [...model.value, ...(data.results || [])]
125
+ const newList = [...modelList.value, ...(data.results || [])]
128
126
 
129
- model.value = newList
127
+ modelList.value = newList
130
128
  offset.value = newList.length
131
129
  count.value = data.count
130
+ modelFields.value = data.fields
132
131
 
133
132
  /**
134
133
  * Sinalizar que houve já uma busca, para evitar que onLoad entre em looping,
@@ -136,7 +135,7 @@ async function fetchList () {
136
135
  */
137
136
  hasMadeFirstFetch.value = true
138
137
 
139
- emit('fetch-success', { list: newList, offset: offset.value, count: count.value })
138
+ emit('fetch-success', { list: newList, fields: modelFields.value, offset: offset.value, count: count.value })
140
139
  } catch (error) {
141
140
  NotifyError('Ops… Não conseguimos acessar as informações. Por favor, tente novamente em alguns minutos.')
142
141
 
@@ -151,7 +150,7 @@ async function fetchList () {
151
150
  function refresh () {
152
151
  count.value = 0
153
152
  offset.value = 0
154
- model.value = []
153
+ modelList.value = []
155
154
 
156
155
  hasMadeFirstFetch.value = false
157
156
 
@@ -162,7 +161,7 @@ function refresh () {
162
161
  }
163
162
 
164
163
  function remove (index) {
165
- model.value.splice(index, 1)
164
+ modelList.value.splice(index, 1)
166
165
  count.value -= 1
167
166
  offset.value -= 1
168
167
  }
@@ -4,6 +4,13 @@ meta:
4
4
  desc: Componente de infinite scroll que implementa o "QInfiniteScroll".
5
5
 
6
6
  props:
7
+ fields:
8
+ desc: Model dos fields.
9
+ default: {}
10
+ type: Object
11
+ examples: [v-model:fields="fields"]
12
+ model: true
13
+
7
14
  list:
8
15
  desc: Model da lista de itens.
9
16
  default: []
@@ -43,10 +43,13 @@
43
43
  <script>
44
44
  import QasFilters from '../filters/QasFilters.vue'
45
45
  import QasPagination from '../pagination/QasPagination.vue'
46
+
47
+ import { viewMixin, contextMixin } from '../../mixins'
48
+
46
49
  import debug from 'debug'
47
50
  import { extend } from 'quasar'
48
51
  import { getState, getAction } from '@bildvitta/store-adapter'
49
- import { viewMixin, contextMixin } from '../../mixins'
52
+ import { computed } from 'vue'
50
53
 
51
54
  const log = debug('asteroid-ui:qas-list-view')
52
55
 
@@ -58,6 +61,13 @@ export default {
58
61
 
59
62
  mixins: [contextMixin, viewMixin],
60
63
 
64
+ provide () {
65
+ return {
66
+ isFetchListSucceeded: computed(() => this.isFetchListSucceeded),
67
+ isListView: true
68
+ }
69
+ },
70
+
61
71
  props: {
62
72
  filtersProps: {
63
73
  default: () => ({}),
@@ -107,7 +117,8 @@ export default {
107
117
  data () {
108
118
  return {
109
119
  page: 1,
110
- resultsQuantity: 0
120
+ resultsQuantity: 0,
121
+ isFetchListSucceeded: false
111
122
  }
112
123
  },
113
124
 
@@ -188,6 +199,7 @@ export default {
188
199
 
189
200
  async fetchList (externalPayload = {}) {
190
201
  this.mx_isFetching = true
202
+ this.isFetchListSucceeded = false
191
203
 
192
204
  try {
193
205
  const payload = {
@@ -215,6 +227,8 @@ export default {
215
227
  metadata: this.mx_metadata
216
228
  })
217
229
 
230
+ this.isFetchListSucceeded = true
231
+
218
232
  this.$emit('fetch-success', response)
219
233
 
220
234
  log(`[${this.entity}]:fetchList:success`, response)
@@ -158,3 +158,12 @@ events:
158
158
  value:
159
159
  desc: Retorna se está ou não fazendo fetching de dados.
160
160
  type: Boolean
161
+
162
+ provide:
163
+ is-fetch-list-succeeded:
164
+ desc: Valor que diz se o `fetchList` foi realizado com sucesso ou não.
165
+ type: Boolean
166
+
167
+ is-list-view:
168
+ desc: Provide que diz quando se está utilizando o listView
169
+ type: Boolean
@@ -1,5 +1,11 @@
1
1
  <template>
2
- <component :is="component.is" v-bind="component.props" />
2
+ <div>
3
+ <div v-if="canShowOptionGroupLabel" class="q-mb-sm text-body1">
4
+ {{ props.label }}
5
+ </div>
6
+
7
+ <component :is="component.is" v-bind="component.props" />
8
+ </div>
3
9
  </template>
4
10
 
5
11
  <script setup>
@@ -10,8 +16,20 @@ defineOptions({
10
16
  inheritAttrs: false
11
17
  })
12
18
 
19
+ const props = defineProps({
20
+ label: {
21
+ default: '',
22
+ type: String
23
+ }
24
+ })
25
+
13
26
  const attrs = useAttrs()
14
27
 
28
+ const isOptionGroup = computed(() => !!attrs.options?.length)
29
+
30
+ // Só mostra a label caso for q-option-group e tenha label vindo nas props
31
+ const canShowOptionGroupLabel = computed(() => isOptionGroup.value && !!props.label)
32
+
15
33
  /**
16
34
  * - quando é um grupo de opções, o componente é 'QOptionGroup', caso contrário,
17
35
  * é 'QRadio'.
@@ -19,16 +37,17 @@ const attrs = useAttrs()
19
37
  * - todos os casos é usado o dense.
20
38
  */
21
39
  const component = computed(() => {
22
- const isOptionGroup = !!attrs.options?.length
23
-
24
40
  const { inline = true, ...payloadProps } = attrs
25
41
 
26
42
  return {
27
- is: isOptionGroup ? 'q-option-group' : 'q-radio',
43
+ is: isOptionGroup.value ? 'q-option-group' : 'q-radio',
44
+
28
45
  props: {
29
46
  ...payloadProps,
30
47
 
31
- ...(isOptionGroup && {
48
+ label: props.label,
49
+
50
+ ...(isOptionGroup.value && {
32
51
  inline,
33
52
  class: {
34
53
  'q-gutter-x-md': inline,
@@ -1,5 +1,11 @@
1
1
  type: component
2
2
 
3
+ props:
4
+ label:
5
+ desc: Label utilizada em casos de ser q-option-group.
6
+ default: ''
7
+ type: String
8
+
3
9
  meta:
4
10
  desc: Componente wrapper do QRadio.
5
11
 
@@ -38,7 +38,7 @@
38
38
  {{ scope.opt.label }}
39
39
  </q-item-label>
40
40
 
41
- <div v-for="(badge, index) in getFilteredBadgeList(scope.opt)" :key="index">
41
+ <div v-for="(badge, index) in getFilteredBadgeList(scope.opt)" :key="index" class="flex">
42
42
  <qas-badge v-if="hasBadge(badge)" v-bind="getBadgeProps(badge)" />
43
43
  </div>
44
44
  </div>
@@ -247,7 +247,16 @@ export default {
247
247
  },
248
248
 
249
249
  canSetDefaultOption () {
250
- return (this.required || this.useAutoSelect) && this.options.length === 1 && !this.modelValue
250
+ // Como o default do model pode ser um array (caso de multiple), é necessário validar o length
251
+ const hasModelValue = Array.isArray(this.modelValue) ? !!this.modelValue.length : !!this.modelValue
252
+
253
+ /**
254
+ * Posso setar o default quando:
255
+ * - O campo for required ou tiver a prop useAutoSelect
256
+ * - Tiver apenas uma option
257
+ * - O modelValue estiver vazio
258
+ */
259
+ return (this.required || this.useAutoSelect) && this.options.length === 1 && !hasModelValue
251
260
  },
252
261
 
253
262
  // redesign
@@ -7,7 +7,7 @@ meta:
7
7
  desc: Componente para select que implementa o "QSelect" repassando propriedades, slots e eventos.
8
8
 
9
9
  props:
10
- badge-list:
10
+ badge-props:
11
11
  desc: Configuração das badges no qual cada key é um callback com o valor booleano retornado pelo back.
12
12
  default: {}
13
13
  examples: ["{ isTester: () => { return { color: 'grey-8', label: 'Tester', textColor: 'white' }} }"]
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <qas-select v-model="internalModel" :label="props.label" :options="props.options" use-filter-mode @update:model-value="onUpdateModel" />
3
+ </template>
4
+
5
+ <script setup>
6
+ import useDefaultFilters from '../../composables/use-default-filters'
7
+
8
+ import { extend } from 'quasar'
9
+ import { watch, ref, nextTick } from 'vue'
10
+ import { useRouter, useRoute } from 'vue-router'
11
+
12
+ defineOptions({ name: 'QasSelectFilter' })
13
+
14
+ const props = defineProps({
15
+ label: {
16
+ type: String,
17
+ default: 'Selecione uma empresa vinculada'
18
+ },
19
+
20
+ name: {
21
+ type: String,
22
+ default: 'company'
23
+ },
24
+
25
+ options: {
26
+ type: Array,
27
+ default: () => []
28
+ }
29
+ })
30
+
31
+ // composables
32
+ const router = useRouter()
33
+ const route = useRoute()
34
+ const { setFilterQuery, triggerDefaultFiltersChange, filterQuery } = useDefaultFilters()
35
+
36
+ // models
37
+ const model = defineModel({ type: String, default: '' })
38
+
39
+ // refs
40
+ const internalModel = ref(route.query[props.name] || model.value)
41
+
42
+ // watch
43
+ watch(() => route.query[props.name], setModels)
44
+
45
+ // functions
46
+ /**
47
+ * Adiciona o valor na URL, atualizando a rota, isto vai fazer com que o componente
48
+ * seja atualizado com o novo valor, pois cai no watch que atualiza o model interno e externo.
49
+ */
50
+ function onUpdateModel (value) {
51
+ const { ...query } = route.query
52
+
53
+ router.push({ query: { ...query, [props.name]: value } })
54
+ }
55
+
56
+ function setModels (value) {
57
+ model.value = value
58
+ internalModel.value = value
59
+
60
+ const oldFilters = extend(true, {}, filterQuery.value)
61
+
62
+ setFilterQuery(value, props.name)
63
+ nextTick(() => triggerDefaultFiltersChange(filterQuery.value, oldFilters))
64
+ }
65
+ </script>
@@ -0,0 +1,36 @@
1
+ type: component
2
+
3
+ meta:
4
+ desc: Componente para gerar dinamicamente checkbox agrupados.
5
+
6
+ props:
7
+ inline:
8
+ desc: Controla se o componente vai aparece em linha ou em bloco.
9
+ default: true
10
+ type: Boolean
11
+
12
+ label:
13
+ desc: Label utilizada em casos de ser checkbox-group.
14
+ default: ''
15
+ type: String
16
+
17
+ model-value:
18
+ desc: Model do componente, usado para v-model.
19
+ default: []
20
+ type: Array
21
+ examples: [v-model"value"]
22
+ model: true
23
+
24
+ options:
25
+ desc: Opções para gerar os checkbox.
26
+ default: []
27
+ type: Array
28
+
29
+ events:
30
+ '@update:model-value -> function(value)':
31
+ desc: Dispara quando o model-value altera, também usado para v-model.
32
+ params:
33
+ value:
34
+ desc: Novo valor do model.
35
+ default: []
36
+ type: Array
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="qas-stepper" :class="classes">
3
- <q-stepper ref="stepper" v-model="model" active-color="primary" active-icon="none" animated :contracted="screen.untilLarge" done-color="primary" done-icon="none" flat :header-class="headerClass" inactive-color="grey-6" keep-alive>
3
+ <q-stepper ref="stepper" v-model="model" v-bind="stepperProps">
4
4
  <template v-for="(_, name) in $slots" #[name]="context">
5
5
  <slot :name="name" v-bind="getContext(context)" />
6
6
  </template>
@@ -9,7 +9,7 @@
9
9
  </template>
10
10
 
11
11
  <script setup>
12
- import { computed, ref } from 'vue'
12
+ import { computed, ref, useAttrs } from 'vue'
13
13
  import { Spacing } from '../../enums/Spacing'
14
14
  import { gutterValidator } from '../../helpers/private/gutter-validator'
15
15
  import useScreen from '../../composables/use-screen'
@@ -35,6 +35,8 @@ const props = defineProps({
35
35
 
36
36
  const stepper = ref(null)
37
37
 
38
+ const attrs = useAttrs()
39
+
38
40
  const screen = useScreen()
39
41
 
40
42
  const emit = defineEmits(['update:modelValue'])
@@ -53,7 +55,27 @@ const model = computed({
53
55
 
54
56
  const classes = computed(() => ({ 'qas-stepper--disable': props.disable }))
55
57
 
56
- const headerClass = computed(() => `text-subtitle1 q-pb-${props.spacing}`)
58
+ const stepperProps = computed(() => {
59
+ const defaultProps = {
60
+ contracted: screen.untilLarge,
61
+ doneColor: 'primary',
62
+ flat: true,
63
+ animated: true,
64
+ activeColor: 'primary',
65
+ errorIcon: 'sym_r_close',
66
+ errorColor: 'white',
67
+ headerClass: `text-subtitle1 q-pb-${props.spacing}`,
68
+ inactiveColor: attrs['header-nav'] || attrs.headerNav ? 'grey-10' : 'grey-6'
69
+ }
70
+
71
+ return {
72
+ activeIcon: 'none',
73
+ doneIcon: 'none',
74
+ keepAlive: true,
75
+ ...attrs,
76
+ ...defaultProps
77
+ }
78
+ })
57
79
 
58
80
  function getContext (context) {
59
81
  return {
@@ -87,6 +109,31 @@ function previous () {
87
109
 
88
110
  &__tab {
89
111
  padding: 0;
112
+
113
+ &--active {
114
+ .q-icon {
115
+ font-size: 14px;
116
+ color: white;
117
+ }
118
+
119
+ .q-stepper__dot {
120
+ background-color: var(--q-primary) !important;
121
+ }
122
+ }
123
+
124
+ &:not(.q-stepper__tab--active).q-stepper__tab--error-with-icon {
125
+ .q-stepper__title {
126
+ color: $grey-10;
127
+ }
128
+
129
+ .q-stepper__dot {
130
+ background-color: $negative !important;
131
+ }
132
+
133
+ .q-icon {
134
+ font-size: 14px;
135
+ }
136
+ }
90
137
  }
91
138
 
92
139
  &__caption {
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <qas-stepper ref="stepper" v-model="model" v-bind="stepperProps">
3
3
  <template #default>
4
- <q-step v-for="(step, stepIndex) in props.steps" :key="stepIndex" :done="isDone(stepIndex)" :name="getStepName(stepIndex)" v-bind="stepPropsList[stepIndex]">
4
+ <q-step v-for="(step, stepIndex) in props.steps" :key="stepIndex" :done="isDone(stepIndex)" :name="getStepName({ step, stepIndex })" v-bind="stepPropsList[stepIndex]">
5
5
  <component :is="step.component" />
6
6
  </q-step>
7
7
  </template>
@@ -30,7 +30,9 @@ const props = defineProps({
30
30
  }
31
31
  })
32
32
 
33
- const model = defineModel({ type: Number, default: 1 })
33
+ defineExpose({ setStepProps })
34
+
35
+ const model = defineModel({ type: [Number, String], default: 1 })
34
36
 
35
37
  const values = ref({})
36
38
  const stepPropsList = ref([])
@@ -68,8 +70,8 @@ function isDone (stepIndex) {
68
70
  return model.value > stepIndex + 1
69
71
  }
70
72
 
71
- function getStepName (stepIndex) {
72
- return stepIndex + 1
73
+ function getStepName ({ step, stepIndex }) {
74
+ return step.name || stepIndex + 1
73
75
  }
74
76
 
75
77
  provide('stepper', {
@@ -17,7 +17,7 @@ props:
17
17
  desc: Propriedades que serão repassadas para o QasStepper.
18
18
  type: Object
19
19
 
20
- inject:
20
+ provide:
21
21
  stepper-model:
22
22
  desc: Model do stepper caso precise recuperar o step atual para alguma lógica. Possui reatividade, portanto para acessar é necessário do ".value"
23
23
  type: Number
@@ -138,6 +138,9 @@ export default {
138
138
 
139
139
  attributes () {
140
140
  const attributes = {
141
+ tableClass: {
142
+ 'overflow-hidden-y': !this.useStickyHeader
143
+ },
141
144
  class: this.tableClass,
142
145
  columns: this.columnsByFields,
143
146
  flat: true,
@@ -2,7 +2,17 @@
2
2
  <div ref="parent" :class="classes">
3
3
  <div class="no-wrap row text-no-wrap">
4
4
  <div ref="truncate" class="ellipsis">
5
- <slot>{{ formattedText }}</slot>
5
+ <slot>
6
+ <div v-if="hasBadges" class="items-center q-col-gutter-sm row" :class="badgeParentClasses">
7
+ <div v-for="(item, index) in normalizedBadgesList" :key="index">
8
+ <qas-badge v-bind="getBadgeProps(item)" />
9
+ </div>
10
+ </div>
11
+
12
+ <div v-else class="ellipsis">
13
+ {{ formattedText }}
14
+ </div>
15
+ </slot>
6
16
  </div>
7
17
 
8
18
  <qas-btn v-if="hasButton" class="q-ml-sm" :label="buttonLabel" @click.stop.prevent="toggle" />
@@ -10,7 +20,7 @@
10
20
 
11
21
  <qas-dialog v-model="show" v-bind="defaultProps" aria-label="Diálogo de texto completo" role="dialog">
12
22
  <template v-if="isCounterMode" #description>
13
- <div class="q-col-gutter-y-md row">
23
+ <div class="q-col-gutter-y-sm row">
14
24
  <div
15
25
  v-for="(item, index) in normalizedList"
16
26
  :key="index"
@@ -25,17 +35,19 @@
25
35
  </template>
26
36
 
27
37
  <script setup>
38
+ import QasDialog from '../dialog/QasDialog.vue'
39
+
40
+ import { baseProps } from '../../shared/badge-config'
41
+
28
42
  import {
29
43
  computed,
44
+ nextTick,
30
45
  onMounted,
31
46
  onUnmounted,
32
47
  ref,
33
48
  watch
34
49
  } from 'vue'
35
50
 
36
- import QasDialog from '../dialog/QasDialog.vue'
37
-
38
- // define component name
39
51
  defineOptions({ name: 'QasTextTruncate' })
40
52
 
41
53
  // props
@@ -55,6 +67,11 @@ const props = defineProps({
55
67
  default: ''
56
68
  },
57
69
 
70
+ emptyText: {
71
+ type: String,
72
+ default: '-'
73
+ },
74
+
58
75
  maxWidth: {
59
76
  type: Number,
60
77
  default: 0
@@ -85,13 +102,16 @@ const props = defineProps({
85
102
  default: () => []
86
103
  },
87
104
 
105
+ useBadge: {
106
+ type: Boolean
107
+ },
108
+
88
109
  useObjectList: {
89
110
  type: Boolean
90
111
  },
91
112
 
92
- emptyText: {
93
- type: String,
94
- default: '-'
113
+ useWrapBadge: {
114
+ type: Boolean
95
115
  }
96
116
  })
97
117
 
@@ -100,11 +120,18 @@ const truncate = ref(null)
100
120
  const parent = ref(null)
101
121
 
102
122
  // composable
123
+ const {
124
+ hasBadges,
125
+ badgeParentClasses,
126
+ normalizedBadgesList,
127
+ getBadgeProps
128
+ } = useBadgeHandler()
129
+
103
130
  const {
104
131
  textContent,
105
132
  isTruncated,
106
133
  truncateText
107
- } = useTruncate({ parent, props })
134
+ } = useTruncate({ parent, props, hasBadges })
108
135
 
109
136
  const {
110
137
  defaultProps,
@@ -122,6 +149,7 @@ const {
122
149
 
123
150
  useMutationObserver({ truncate, callbackFn: truncateText })
124
151
 
152
+ // computeds
125
153
  const classes = computed(() => [`text-${props.color}`, `text-${props.typography}`])
126
154
 
127
155
  const formattedText = computed(() => props.list.length || props.text ? displayText.value : props.emptyText)
@@ -182,7 +210,7 @@ function useMutationObserver ({ truncate, callbackFn = () => {} }) {
182
210
  }
183
211
  }
184
212
 
185
- function useTruncate ({ parent, props }) {
213
+ function useTruncate ({ parent, props, hasBadges }) {
186
214
  // reactive vars
187
215
  const maxPossibleWidth = ref('')
188
216
  const textContent = ref('')
@@ -191,14 +219,19 @@ function useTruncate ({ parent, props }) {
191
219
  // lifecycle
192
220
  onMounted(() => truncateText())
193
221
 
194
- // watch
195
- watch(() => props.maxWidth, truncateText)
196
-
197
222
  // computed
198
223
  const isTruncated = computed(() => textWidth.value > maxPossibleWidth.value)
199
224
 
225
+ // watch
226
+ watch(() => props.maxWidth, truncateText)
227
+
200
228
  // functions
201
- function truncateText () {
229
+ async function truncateText () {
230
+ await nextTick()
231
+
232
+ // Se tiver badges, então não pode ser feito calculo de width.
233
+ if (hasBadges.value) return
234
+
202
235
  parent.value.style.maxWidth = '100%'
203
236
  textWidth.value = truncate.value.clientWidth
204
237
  textContent.value = truncate.value?.innerHTML
@@ -271,4 +304,34 @@ function useCounter () {
271
304
  counterLabel
272
305
  }
273
306
  }
307
+
308
+ function useBadgeHandler () {
309
+ const hasBadges = computed(() => props.useBadge && props.useObjectList && props.list.length)
310
+
311
+ const normalizedBadgesList = computed(() => props.list.slice(0, props.maxVisibleItem))
312
+ const badgeParentClasses = computed(() => ({ 'no-wrap': !props.useWrapBadge }))
313
+
314
+ function getBadgeProps (item) {
315
+ const itemProps = {}
316
+
317
+ /**
318
+ * recupera somente keys que estão em baseProps do QasBadge
319
+ * pra evitar que passe propriedades desnecessárias
320
+ */
321
+ for (const key in item) {
322
+ if (baseProps[key]) {
323
+ itemProps[key] = item[key]
324
+ }
325
+ }
326
+
327
+ return itemProps
328
+ }
329
+
330
+ return {
331
+ hasBadges,
332
+ badgeParentClasses,
333
+ normalizedBadgesList,
334
+ getBadgeProps
335
+ }
336
+ }
274
337
  </script>