@bildvitta/quasar-ui-asteroid 3.11.0-beta.9 → 3.11.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 (39) hide show
  1. package/package.json +1 -1
  2. package/src/assets/icon-loading.svg +1 -0
  3. package/src/components/actions-menu/QasActionsMenu.vue +1 -1
  4. package/src/components/copy/QasCopy.vue +1 -1
  5. package/src/components/date-time-input/QasDateTimeInput.vue +13 -3
  6. package/src/components/date-time-input/QasDateTimeInput.yml +10 -0
  7. package/src/components/delete/QasDelete.vue +1 -1
  8. package/src/components/dialog/QasDialog.vue +11 -1
  9. package/src/components/field/QasField.vue +5 -16
  10. package/src/components/form-generator/QasFormGenerator.vue +2 -0
  11. package/src/components/form-generator/QasFormGenerator.yml +1 -1
  12. package/src/components/form-view/QasFormView.vue +17 -1
  13. package/src/components/form-view/QasFormView.yml +6 -0
  14. package/src/components/input/QasInput.vue +58 -16
  15. package/src/components/input/QasInput.yml +11 -0
  16. package/src/components/label/QasLabel.vue +13 -5
  17. package/src/components/label/QasLabel.yml +10 -0
  18. package/src/components/numeric-input/QasNumericInput.vue +18 -4
  19. package/src/components/numeric-input/QasNumericInput.yml +11 -1
  20. package/src/components/page-header/QasPageHeader.vue +2 -1
  21. package/src/components/search-input/QasSearchInput.vue +1 -1
  22. package/src/components/select/QasSelect.vue +15 -0
  23. package/src/components/select/QasSelect.yml +10 -0
  24. package/src/components/select-list/QasSelectList.vue +6 -4
  25. package/src/components/select-list/QasSelectList.yml +9 -2
  26. package/src/components/sortable/QasSortable.vue +20 -17
  27. package/src/components/sortable/QasSortable.yml +12 -12
  28. package/src/components/text-truncate/QasTextTruncate.vue +1 -1
  29. package/src/components/tree-generator/QasTreeGenerator.vue +1 -1
  30. package/src/components/welcome/QasWelcome.vue +22 -5
  31. package/src/components/welcome/QasWelcome.yml +9 -0
  32. package/src/css/base/font-face.scss +28 -0
  33. package/src/css/base/index.scss +1 -0
  34. package/src/css/components/button.scss +2 -2
  35. package/src/helpers/get-required-label.js +3 -0
  36. package/src/helpers/index.js +1 -0
  37. package/src/index.scss +3 -0
  38. package/src/mixins/search-filter.js +1 -1
  39. package/src/plugins/delete/Delete.js +12 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
3
  "description": "Asteroid",
4
- "version": "3.11.0-beta.9",
4
+ "version": "3.11.0",
5
5
  "author": "Bild & Vitta <systemteam@bild.com.br>",
6
6
  "license": "MIT",
7
7
  "main": "dist/asteroid.cjs.min.js",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="#90a4ae" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-80q-84 0-157-31t-127-85q-54-54-85-127T80-480q0-84 31-157t85-127q54-54 127-85t157-31q12 0 21 9t9 21q0 12-9 21t-21 9q-141 0-240.5 99.5T140-480q0 141 99.5 240.5T480-140q141 0 240.5-99.5T820-480q0-12 9-21t21-9q12 0 21 9t9 21q0 84-31 157t-85 127q-54 54-127 85T480-80Z"/></svg>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div v-if="hasActions" class="qas-actions-menu">
3
- <component :is="component.is" v-bind="component.props" variant="tertiary">
3
+ <component :is="component.is" v-bind="component.props" variant="tertiary" @click.stop.prevent>
4
4
  <q-list v-if="isBtnDropdown">
5
5
  <slot v-for="(item, key) in actions" :item="item" :name="key">
6
6
  <q-item v-bind="item.props" :key="key" clickable @click="onClick(item)">
@@ -2,7 +2,7 @@
2
2
  <span>
3
3
  <slot>{{ text }}</slot>
4
4
 
5
- <qas-btn class="q-ml-xs" color="primary" :icon="icon" :loading="isLoading" variant="tertiary" @click.stop="copy">
5
+ <qas-btn class="q-ml-xs" color="primary" :icon="icon" :loading="isLoading" variant="tertiary" @click.stop.prevent="copy">
6
6
  <q-tooltip>Copiar</q-tooltip>
7
7
  </qas-btn>
8
8
  </span>
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <qas-input ref="input" v-bind="attributes" v-model="currentValue" :unmasked-value="false" @blur="validateDateTimeOnBlur" @focus="resetError" @update:model-value="updateModelValue">
2
+ <qas-input ref="input" v-bind="attributes" v-model="currentValue" inputmode="numeric" :unmasked-value="false" @blur="validateDateTimeOnBlur" @focus="resetError" @update:model-value="updateModelValue">
3
3
  <template #append>
4
4
  <qas-btn v-if="!useTimeOnly" color="grey-9" :disable="$attrs.readonly" icon="sym_r_event" variant="tertiary">
5
- <q-popup-proxy ref="dateProxy" transition-hide="scale" transition-show="scale">
5
+ <q-popup-proxy ref="dateProxy" transition-hide="scale" transition-show="scale" v-bind="datePopupProxyProps">
6
6
  <qas-date v-model="currentValue" v-bind="defaultDateProps" :mask="maskDate" width="290px" @update:model-value="updateModelValue" />
7
7
  </q-popup-proxy>
8
8
  </qas-btn>
9
9
 
10
10
  <qas-btn v-if="!useDateOnly" class="q-ml-sm" color="grey-9" :disable="$attrs.readonly" icon="sym_r_access_time">
11
- <q-popup-proxy ref="timeProxy" transition-hide="scale" transition-show="scale">
11
+ <q-popup-proxy ref="timeProxy" transition-hide="scale" transition-show="scale" v-bind="timePopupProxyProps">
12
12
  <q-time v-model="currentValue" v-bind="defaultTimeProps" format24h :mask="maskDate" @update:model-value="updateModelValue" />
13
13
  </q-popup-proxy>
14
14
  </qas-btn>
@@ -36,6 +36,11 @@ export default {
36
36
  type: Object
37
37
  },
38
38
 
39
+ datePopupProxyProps: {
40
+ default: () => ({}),
41
+ type: Object
42
+ },
43
+
39
44
  timeMask: {
40
45
  default: 'HH:mm',
41
46
  type: String
@@ -46,6 +51,11 @@ export default {
46
51
  type: Object
47
52
  },
48
53
 
54
+ timePopupProxyProps: {
55
+ default: () => ({}),
56
+ type: Object
57
+ },
58
+
49
59
  useIso: {
50
60
  type: Boolean
51
61
  },
@@ -17,6 +17,11 @@ props:
17
17
  default: {}
18
18
  type: Object
19
19
 
20
+ date-popup-proxy-props:
21
+ desc: Propriedades do QPopupProxy para o popup do QDate (https://quasar.dev/vue-components/popup-proxy#qpopupproxy-api).
22
+ default: {}
23
+ type: Object
24
+
20
25
  model-value:
21
26
  desc: Model do componente, usado para v-model.
22
27
  default: ''
@@ -33,6 +38,11 @@ props:
33
38
  default: {}
34
39
  type: Object
35
40
 
41
+ time-popup-proxy-props:
42
+ desc: Propriedades do QPopupProxy para o popup do QTime (https://quasar.dev/vue-components/popup-proxy#qpopupproxy-api).
43
+ default: {}
44
+ type: Object
45
+
36
46
  use-time-only:
37
47
  desc: Habilita o componente para usar somente hora.
38
48
  type: Boolean
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <component v-bind="attributes" :is="tag" @click.stop="onDelete">
2
+ <component v-bind="attributes" :is="tag" @click.stop.prevent="onDelete">
3
3
  <template v-for="(_, name) in $slots" #[name]="context">
4
4
  <slot :name="name" v-bind="context || {}" />
5
5
  </template>
@@ -14,7 +14,7 @@
14
14
  <section class="text-body1 text-grey-8">
15
15
  <component :is="componentTag" ref="form">
16
16
  <slot name="description">
17
- <div v-if="card.description">{{ card.description }}</div>
17
+ <component :is="descriptionComponentTag">{{ card.description }}</component>
18
18
  </slot>
19
19
  </component>
20
20
  </section>
@@ -186,6 +186,16 @@ export default {
186
186
  useEqualWidth: this.hasAllActions,
187
187
  ...this.actionsProps
188
188
  }
189
+ },
190
+
191
+ hasRenderFunction () {
192
+ const description = this.card.description
193
+
194
+ return typeof description === 'object' && description !== null && !Array.isArray(description)
195
+ },
196
+
197
+ descriptionComponentTag () {
198
+ return this.hasRenderFunction ? this.card.description : 'div'
189
199
  }
190
200
  },
191
201
 
@@ -70,10 +70,12 @@ export default {
70
70
  name,
71
71
  options,
72
72
  readonly,
73
+ required,
73
74
  disable,
74
75
  filled = readonly,
75
76
  suffix,
76
77
  prefix,
78
+ places,
77
79
  type,
78
80
  mask,
79
81
  maxFiles,
@@ -95,6 +97,7 @@ export default {
95
97
  outlined: true,
96
98
  ...error,
97
99
  readonly,
100
+ required,
98
101
  disable,
99
102
  filled,
100
103
  maxlength,
@@ -104,7 +107,7 @@ export default {
104
107
  useIso
105
108
  }
106
109
 
107
- const numericInput = { is: 'qas-numeric-input', ...input }
110
+ const numericInput = { is: 'qas-numeric-input', places, ...input }
108
111
  const datetimeInput = { is: 'qas-date-time-input', useIso, ...input }
109
112
 
110
113
  // It'll generate a list of acceptable files extensions.
@@ -151,8 +154,7 @@ export default {
151
154
 
152
155
  return {
153
156
  ...(profiles[type] || profiles.default),
154
- ...this.$attrs,
155
- label: this.formattedLabel
157
+ ...this.$attrs
156
158
  }
157
159
  },
158
160
 
@@ -160,19 +162,6 @@ export default {
160
162
  return Array.isArray(this.error) ? this.error.join(' ') : this.error
161
163
  },
162
164
 
163
- formattedLabel () {
164
- const nonRequiredFieldsLabel = ['boolean', 'checkbox', 'radio']
165
-
166
- const label = this.$attrs.label || this.formattedField.label
167
- const { required, type } = this.formattedField
168
-
169
- if (required && label && !nonRequiredFieldsLabel.includes(type)) {
170
- return `${label}*`
171
- }
172
-
173
- return label
174
- },
175
-
176
165
  // This computed will change the key name when the server sends different key.
177
166
  formattedField () {
178
167
  const field = {}
@@ -3,6 +3,7 @@
3
3
  <div v-for="(fieldsetItem, fieldsetItemKey) in normalizedFields" :key="fieldsetItemKey" class="full-width">
4
4
  <slot v-if="fieldsetItem.label" :name="`legend-${fieldsetItemKey}`">
5
5
  <qas-label :label="fieldsetItem.label" />
6
+ <div v-if="fieldsetItem.description" class="q-mb-md text-body1 text-grey-8">{{ fieldsetItem.description }}</div>
6
7
  </slot>
7
8
 
8
9
  <div>
@@ -123,6 +124,7 @@ const normalizedFields = computed(() => {
123
124
 
124
125
  fields[fieldsetKey] = {
125
126
  label: fieldsetItem.label,
127
+ description: fieldsetItem.description,
126
128
  fields: { hidden: {}, visible: {} }
127
129
  }
128
130
 
@@ -36,7 +36,7 @@ props:
36
36
  desc: Lista para agrupar elementos por rótulo (label).
37
37
  default: {}
38
38
  type: Object
39
- examples: ["{ personalInformation: { label: 'Informações pessoais', fields: [name, email] } }"]
39
+ examples: ["{ personalInformation: { label: 'Informações pessoais', description: 'Descrição dos campos', fields: ['name', 'email'] } }"]
40
40
 
41
41
  fieldset-gutter:
42
42
  desc: Espaçamento entre rótulos (label).
@@ -4,7 +4,7 @@
4
4
  <slot name="header" />
5
5
  </header>
6
6
 
7
- <q-form ref="form" @submit="submitHandler">
7
+ <q-form ref="form" v-bind="defaultFormProps">
8
8
  <slot />
9
9
 
10
10
  <slot v-if="useActions" name="actions">
@@ -76,6 +76,11 @@ export default {
76
76
  type: Boolean
77
77
  },
78
78
 
79
+ formProps: {
80
+ type: Object,
81
+ default: () => ({})
82
+ },
83
+
79
84
  mode: {
80
85
  default: 'create',
81
86
  type: String
@@ -191,6 +196,17 @@ export default {
191
196
  error: 'Não conseguimos salvar as informações. Por favor, tente novamente em alguns minutos.',
192
197
  success: 'Informações salvas com sucesso.'
193
198
  }
199
+ },
200
+
201
+ defaultFormProps () {
202
+ return {
203
+ ...this.formProps,
204
+
205
+ onSubmit: event => {
206
+ this.submitHandler(event)
207
+ this.formProps?.onSubmit?.(event)
208
+ }
209
+ }
194
210
  }
195
211
  },
196
212
 
@@ -66,6 +66,12 @@ props:
66
66
  examples: [v-model:fields="fields"]
67
67
  model: true
68
68
 
69
+ form-props:
70
+ desc: Repassa todas as props/eventos para o `QForm`.
71
+ default: {}
72
+ type: Object
73
+ examples: ['{ onValidationError: ref => validationErrorHandler(ref) }']
74
+
69
75
  ignore-keys-in-unsaved-changes:
70
76
  desc: Vamos imaginar um cenário onde você precisa alterar valores do v-model por qualquer motivo que seja, mas quando o usuário sair da tela, não pode aparecer o modal perguntando se ele quer sair ou continuar editando, por que o usuário de fato não fez nenhuma alteração nos dados, esta prop serve para você dizer quais keys dentro do v-model você quer ignorar.
71
77
  default: []
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <q-input ref="input" v-model="model" bottom-slots :error="errorData" v-bind="$attrs" :error-message="errorMessage" :mask="mask" :outlined="outlined" :unmasked-value="unmaskedValue" @paste="onPaste">
2
+ <q-input ref="input" v-model="model" bottom-slots :error="errorData" v-bind="$attrs" :error-message="errorMessage" :inputmode="defaultInputmode" :label="formattedLabel" :mask="currentMask" :outlined="outlined" :unmasked-value="unmaskedValue" @paste="onPaste">
3
3
  <template v-for="(_, name) in $slots" #[name]="context">
4
4
  <slot :name="name" v-bind="context || {}" />
5
5
  </template>
@@ -7,6 +7,16 @@
7
7
  </template>
8
8
 
9
9
  <script>
10
+ import { getRequiredLabel } from '../../helpers'
11
+
12
+ const Masks = {
13
+ CompanyDocument: 'company-document',
14
+ Document: 'document',
15
+ PersonalDocument: 'personal-document',
16
+ Phone: 'phone',
17
+ PostalCode: 'postal-code'
18
+ }
19
+
10
20
  export default {
11
21
  name: 'QasInput',
12
22
 
@@ -22,6 +32,11 @@ export default {
22
32
  default: ''
23
33
  },
24
34
 
35
+ mask: {
36
+ type: String,
37
+ default: ''
38
+ },
39
+
25
40
  modelValue: {
26
41
  default: '',
27
42
  type: [String, Number]
@@ -32,6 +47,10 @@ export default {
32
47
  type: Boolean
33
48
  },
34
49
 
50
+ required: {
51
+ type: Boolean
52
+ },
53
+
35
54
  unmaskedValue: {
36
55
  default: true,
37
56
  type: Boolean
@@ -47,7 +66,8 @@ export default {
47
66
  data () {
48
67
  return {
49
68
  errorData: false,
50
- mask: ''
69
+ currentMask: '',
70
+ inputReference: null
51
71
  }
52
72
  },
53
73
 
@@ -56,20 +76,33 @@ export default {
56
76
  return this.inputReference.hasError
57
77
  },
58
78
 
59
- inputReference () {
60
- return this.$refs.input
61
- },
62
-
63
79
  masks () {
64
80
  return {
65
- 'company-document': () => '##.###.###/####-##',
66
- document: () => this.toggleMask('###.###.###-###', '##.###.###/####-##'),
67
- 'personal-document': () => '###.###.###-##',
68
- phone: () => this.toggleMask('(##) ####-#####', '(##) #####-####'),
69
- 'postal-code': () => '#####-###'
81
+ [Masks.CompanyDocument]: () => '##.###.###/####-##',
82
+ [Masks.Document]: () => this.toggleMask('###.###.###-###', '##.###.###/####-##'),
83
+ [Masks.PersonalDocument]: () => '###.###.###-##',
84
+ [Masks.Phone]: () => this.toggleMask('(##) ####-#####', '(##) #####-####'),
85
+ [Masks.PostalCode]: () => '#####-###'
70
86
  }
71
87
  },
72
88
 
89
+ defaultInputmode () {
90
+ const { inputmode, type } = this.$attrs
91
+
92
+ const defaults = {
93
+ [Masks.CompanyDocument]: 'numeric',
94
+ [Masks.Document]: 'numeric',
95
+ [Masks.PersonalDocument]: 'numeric',
96
+ [Masks.Phone]: 'tel',
97
+ [Masks.PostalCode]: 'numeric',
98
+
99
+ // types
100
+ email: 'email'
101
+ }
102
+
103
+ return inputmode || defaults[this.mask || type]
104
+ },
105
+
73
106
  model: {
74
107
  get () {
75
108
  return this.modelValue
@@ -80,11 +113,17 @@ export default {
80
113
 
81
114
  return this.$emit('update:modelValue', value)
82
115
  }
116
+ },
117
+
118
+ formattedLabel () {
119
+ const { label } = this.$attrs
120
+
121
+ return getRequiredLabel({ label, required: this.required })
83
122
  }
84
123
  },
85
124
 
86
125
  watch: {
87
- mask (value) {
126
+ currentMask (value) {
88
127
  if (!value) return
89
128
 
90
129
  const input = this.getInput()
@@ -110,6 +149,10 @@ export default {
110
149
  }
111
150
  },
112
151
 
152
+ mounted () {
153
+ this.inputReference = this.$refs.input
154
+ },
155
+
113
156
  methods: {
114
157
  focus () {
115
158
  return this.inputReference.focus()
@@ -129,7 +172,7 @@ export default {
129
172
  },
130
173
 
131
174
  onPaste (event) {
132
- if (!this.mask) return
175
+ if (!this.currentMask) return
133
176
 
134
177
  const value = event.clipboardData.getData('text')
135
178
  const input = this.getInput()
@@ -153,11 +196,10 @@ export default {
153
196
  handleMask () {
154
197
  if (!this.modelValue?.length) return
155
198
 
156
- const { mask } = this.$attrs
157
- const hasDefaultMask = Object.prototype.hasOwnProperty.call(this.masks, mask)
199
+ const hasDefaultMask = Object.prototype.hasOwnProperty.call(this.masks, this.mask)
158
200
 
159
201
  this.$nextTick(() => {
160
- this.mask = hasDefaultMask ? this.masks[mask]() : mask
202
+ this.currentMask = hasDefaultMask ? this.masks[this.mask]() : this.mask
161
203
  })
162
204
  }
163
205
  }
@@ -15,6 +15,12 @@ props:
15
15
  desc: Controla cor da borda do input.
16
16
  type: Boolean
17
17
 
18
+ mask:
19
+ desc: Máscara do input, é possível passar um slug de mascara ou um pattern personalizado.
20
+ type: String
21
+ default: ''
22
+ examples: [document, personal-document, company-document, phone, postal-code, '##/##/####']
23
+
18
24
  model-value:
19
25
  desc: Model do componente.
20
26
  type: [String, Input]
@@ -26,6 +32,11 @@ props:
26
32
  default: true
27
33
  type: Boolean
28
34
 
35
+ required:
36
+ desc: Controla label do campo, se for "true" adiciona sufixo "*".
37
+ default: false
38
+ type: Boolean
39
+
29
40
  use-remove-error-on-type:
30
41
  desc: Limpa os erros do campo caso os mesmos existam toda vez que o model atualiza.
31
42
  type: Boolean
@@ -1,17 +1,22 @@
1
1
  <template>
2
2
  <div class="text-h4" :class="classes">
3
- <slot :label-with-suffix="labelWithSuffix">{{ labelWithSuffix }}</slot>
3
+ <slot :label-with-suffix="formattedLabel">{{ formattedLabel }}</slot>
4
4
  </div>
5
5
  </template>
6
6
 
7
7
  <script>
8
- import { addCounterSuffix } from '../../helpers'
8
+ import { addCounterSuffix, getRequiredLabel } from '../../helpers'
9
9
  import { Spacing } from '../../enums/Spacing'
10
10
 
11
11
  export default {
12
12
  name: 'QasLabel',
13
13
 
14
14
  props: {
15
+ color: {
16
+ type: String,
17
+ default: 'grey-9'
18
+ },
19
+
15
20
  count: {
16
21
  default: 0,
17
22
  type: [Number, String]
@@ -32,9 +37,8 @@ export default {
32
37
  }
33
38
  },
34
39
 
35
- color: {
36
- type: String,
37
- default: 'grey-9'
40
+ required: {
41
+ type: Boolean
38
42
  }
39
43
  },
40
44
 
@@ -43,6 +47,10 @@ export default {
43
47
  return addCounterSuffix(this.label, parseFloat(this.count))
44
48
  },
45
49
 
50
+ formattedLabel () {
51
+ return getRequiredLabel({ label: this.labelWithSuffix, required: this.required })
52
+ },
53
+
46
54
  classes () {
47
55
  return [
48
56
  `q-mb-${this.margin}`,
@@ -19,6 +19,16 @@ props:
19
19
  type: String
20
20
  examples: [xs, sm, md, lg, xl]
21
21
 
22
+ required:
23
+ desc: Controla label do campo, se for "true" adiciona sufixo "*".
24
+ default: false
25
+ type: Boolean
26
+
27
+ color:
28
+ desc: Cor da label.
29
+ default: grey-9
30
+ type: String
31
+
22
32
  slots:
23
33
  default:
24
34
  desc: Slot para acessar elemento do texto.
@@ -1,13 +1,14 @@
1
1
  <template>
2
- <q-field :model-value="modelValue" outlined>
2
+ <q-field :label="formattedLabel" :model-value="modelValue" outlined>
3
3
  <template #control="{ floatingLabel, id }">
4
- <input v-show="floatingLabel" :id="id" ref="input" class="q-field__input" @blur="emitValue" @click="setSelect" @input="emitUpdateModel($event.target.value)">
4
+ <input v-show="floatingLabel" :id="id" ref="input" class="q-field__input" inputmode="numeric" @blur="emitValue" @click="setSelect" @input="emitUpdateModel($event.target.value)">
5
5
  </template>
6
6
  </q-field>
7
7
  </template>
8
8
 
9
9
  <script>
10
10
  import AutoNumeric from 'autonumeric'
11
+ import { getRequiredLabel } from '../../helpers'
11
12
 
12
13
  const defaultModes = {
13
14
  decimal: 'commaDecimalCharDotSeparator',
@@ -25,11 +26,16 @@ export default {
25
26
  type: Object
26
27
  },
27
28
 
28
- decimalPlaces: {
29
+ places: {
29
30
  default: 2,
30
31
  type: Number
31
32
  },
32
33
 
34
+ label: {
35
+ type: String,
36
+ default: ''
37
+ },
38
+
33
39
  mode: {
34
40
  default: 'integer',
35
41
  type: String,
@@ -54,6 +60,10 @@ export default {
54
60
  type: [Boolean, String]
55
61
  },
56
62
 
63
+ required: {
64
+ type: Boolean
65
+ },
66
+
57
67
  useNegative: {
58
68
  type: Boolean
59
69
  },
@@ -78,6 +88,10 @@ export default {
78
88
  computed: {
79
89
  defaultMode () {
80
90
  return defaultModes[this.mode]
91
+ },
92
+
93
+ formattedLabel () {
94
+ return getRequiredLabel({ label: this.label, required: this.required })
81
95
  }
82
96
  },
83
97
 
@@ -113,7 +127,7 @@ export default {
113
127
  }
114
128
 
115
129
  if (this.mode !== 'integer') {
116
- options.decimalPlaces = this.decimalPlaces
130
+ options.decimalPlaces = this.places
117
131
  }
118
132
 
119
133
  if (this.mode === 'money') {
@@ -12,11 +12,16 @@ props:
12
12
  default: {}
13
13
  type: Object
14
14
 
15
- decimal-places:
15
+ places:
16
16
  desc: Quantidade de casas decimais.
17
17
  default: 2
18
18
  type: Number
19
19
 
20
+ label:
21
+ desc: Label do componente.
22
+ type: String
23
+ default: ''
24
+
20
25
  mode:
21
26
  desc: Modo do componente.
22
27
  default: integer
@@ -33,6 +38,11 @@ props:
33
38
  desc: Propriedade preset serve para usar configuração de predefinição/nacionalidade da moeda pré setada pelo autonumeric (Brasil é o padrão).
34
39
  type: [Boolean, String]
35
40
 
41
+ required:
42
+ desc: Controla label do campo, se for "true" adiciona sufixo "*".
43
+ default: false
44
+ type: Boolean
45
+
36
46
  use-negative:
37
47
  desc: Controla se pode ou não números negativos.
38
48
  default: false
@@ -9,7 +9,7 @@
9
9
  <q-breadcrumbs v-if="useBreadcrumbs" class="text-caption" gutter="xs" separator-color="grey-8">
10
10
  <q-breadcrumbs-el v-if="useHomeIcon" class="qas-page-header__breadcrumbs-el text-grey-8" icon="sym_r_home" :to="homeRoute" />
11
11
 
12
- <q-breadcrumbs-el v-for="(item, index) in normalizedBreadcrumbs" :key="index" class="qas-page-header__breadcrumbs-el" :label="item.label" :to="item.route" />
12
+ <q-breadcrumbs-el v-for="(item, index) in normalizedBreadcrumbs" :key="index" class="ellipsis inline-block qas-page-header__breadcrumbs-el" :label="item.label" :to="item.route" />
13
13
  </q-breadcrumbs>
14
14
  </div>
15
15
 
@@ -142,6 +142,7 @@ export default {
142
142
  <style lang="scss">
143
143
  .qas-page-header {
144
144
  &__breadcrumbs-el {
145
+ max-width: 180px;
145
146
  transition: color var(--qas-generic-transition);
146
147
 
147
148
  &.q-breadcrumbs__el:not(.q-router-link--exact-active):hover {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="qas-filter-input">
3
- <qas-input ref="input" v-model="model" v-bind="$attrs" class="bg-white rounded-borders-sm" data-cy="search-input" :debounce="debounce" dense hide-bottom-space input-class="ellipsis text-grey-8" type="search">
3
+ <qas-input ref="input" v-model="model" v-bind="$attrs" class="bg-white rounded-borders-sm" data-cy="search-input" :debounce="debounce" dense hide-bottom-space input-class="ellipsis text-grey-8" inputmode="search" type="search">
4
4
  <template #prepend>
5
5
  <q-icon v-if="useSearchOnType" color="grey-8" name="sym_r_search" />
6
6
  <qas-btn v-else color="grey-9" icon="sym_r_search" variant="tertiary" @click="$emit('filter')" />
@@ -29,6 +29,7 @@
29
29
  </template>
30
30
 
31
31
  <script>
32
+ import { getRequiredLabel } from '../../helpers'
32
33
  import { uid } from 'quasar'
33
34
  import { searchFilterMixin } from '../../mixins'
34
35
  import Fuse from 'fuse.js'
@@ -45,6 +46,11 @@ export default {
45
46
  type: Object
46
47
  },
47
48
 
49
+ label: {
50
+ type: String,
51
+ default: ''
52
+ },
53
+
48
54
  modelValue: {
49
55
  default: () => [],
50
56
  type: [Array, Object, String, Number, Boolean]
@@ -60,6 +66,10 @@ export default {
60
66
  type: Array
61
67
  },
62
68
 
69
+ required: {
70
+ type: Boolean
71
+ },
72
+
63
73
  useFetchOptionsOnCreate: {
64
74
  default: true,
65
75
  type: Boolean
@@ -92,6 +102,7 @@ export default {
92
102
 
93
103
  ...this.$attrs,
94
104
 
105
+ label: this.formattedLabel,
95
106
  error: this.hasError,
96
107
  inputDebounce: this.useLazyLoading ? 1200 : 0,
97
108
  loading: this.hasLoading,
@@ -155,6 +166,10 @@ export default {
155
166
 
156
167
  popupContentClass () {
157
168
  return `qas-select__popup-content-${uid()}`
169
+ },
170
+
171
+ formattedLabel () {
172
+ return getRequiredLabel({ label: this.label, required: this.required })
158
173
  }
159
174
  },
160
175
 
@@ -29,6 +29,11 @@ props:
29
29
  keys: [label, value]
30
30
  threshold: 0.4
31
31
 
32
+ label:
33
+ desc: Label do componente.
34
+ type: String
35
+ default: ''
36
+
32
37
  label-key:
33
38
  desc: O componente internamente espera receber na propriedade "options" um array de objeto contendo "label" e "value", caso o seu objeto não tenha "label" mas um "name" por exemplo, você pode definir esta prop "label-key" como "name".
34
39
  type: String
@@ -66,6 +71,11 @@ props:
66
71
  default: []
67
72
  type: Array
68
73
 
74
+ required:
75
+ desc: Controla label do campo, se for "true" adiciona sufixo "*".
76
+ default: false
77
+ type: Boolean
78
+
69
79
  value-key:
70
80
  desc: O componente internamente espera receber na propriedade "options" um array de objeto contendo "label" e "value", caso o seu objeto não tenha "value" mas um "uuid" por exemplo, você pode definir esta prop "label-value" como "uuid".
71
81
  type: String
@@ -83,8 +83,9 @@ export default {
83
83
  },
84
84
 
85
85
  emits: [
86
- 'added',
87
- 'removed',
86
+ 'add',
87
+ 'remove',
88
+ 'clear',
88
89
  'update:modelValue'
89
90
  ],
90
91
 
@@ -167,7 +168,7 @@ export default {
167
168
  this.values.push(this.getNormalizedValue(item))
168
169
  this.updateModel()
169
170
 
170
- this.$emit('added', item)
171
+ this.$emit('add', item)
171
172
  },
172
173
 
173
174
  handleList () {
@@ -193,7 +194,7 @@ export default {
193
194
  this.values.splice(index, 1)
194
195
  this.updateModel()
195
196
 
196
- this.$emit('removed', item, index)
197
+ this.$emit('remove', item, index)
197
198
  },
198
199
 
199
200
  sortList () {
@@ -228,6 +229,7 @@ export default {
228
229
  },
229
230
 
230
231
  clearSelection () {
232
+ this.$emit('clear', this.values)
231
233
  this.values = []
232
234
  this.updateModel()
233
235
  }
@@ -76,14 +76,14 @@ slots:
76
76
  type: Function
77
77
 
78
78
  events:
79
- '@added -> function(item)':
79
+ '@add -> function(item)':
80
80
  desc: Dispara toda vez que um item é adicionado no v-model.
81
81
  params:
82
82
  item:
83
83
  desc: Item adicionado
84
84
  type: String
85
85
 
86
- '@removed -> function (item, index)':
86
+ '@remove -> function (item, index)':
87
87
  desc: Dispara toda vez que um item é removido do v-model.
88
88
  params:
89
89
  item:
@@ -93,6 +93,13 @@ events:
93
93
  desc: Index do item removido.
94
94
  type: Number
95
95
 
96
+ '@clear -> function(oldValue)':
97
+ desc: Dispara toda vez que o v-model é limpo através do botão de "Limpar seleção".
98
+ params:
99
+ oldValue:
100
+ desc: O valor do v-model anterior antes de limpá-lo.
101
+ type: Array
102
+
96
103
  '@update:model-value -> function (value)':
97
104
  desc: Dispara toda vez que o campo de busca é alterado, também utilizado para v-model.
98
105
  params:
@@ -17,7 +17,6 @@ export default {
17
17
  props: {
18
18
  entity: {
19
19
  default: '',
20
- required: true,
21
20
  type: String
22
21
  },
23
22
 
@@ -26,11 +25,6 @@ export default {
26
25
  type: Object
27
26
  },
28
27
 
29
- list: {
30
- default: () => [],
31
- type: Array
32
- },
33
-
34
28
  tag: {
35
29
  default: 'div',
36
30
  type: String
@@ -41,14 +35,19 @@ export default {
41
35
  type: String
42
36
  },
43
37
 
44
- sorted: {
38
+ modelValue: {
45
39
  default: () => [],
46
40
  type: Array
41
+ },
42
+
43
+ useSaveOnSort: {
44
+ type: Boolean,
45
+ default: true
47
46
  }
48
47
  },
49
48
 
50
49
  emits: [
51
- 'update:sorted',
50
+ 'update:modelValue',
52
51
  'sort',
53
52
  'success',
54
53
  'error'
@@ -72,9 +71,12 @@ export default {
72
71
  this.sortable.options = { ...this.sortable.options, ...value }
73
72
  },
74
73
 
75
- list (value) {
76
- this.setSortedValue(value)
77
- this.sortable.sort(this.sortable.toArray())
74
+ modelValue: {
75
+ handler (newValues) {
76
+ this.sortedList = newValues
77
+ },
78
+
79
+ deep: true
78
80
  }
79
81
  },
80
82
 
@@ -132,16 +134,17 @@ export default {
132
134
  const deleted = this.sortedList.splice(oldIndex, 1)
133
135
  this.sortedList.splice(newIndex, 0, deleted[0])
134
136
 
135
- this.replace()
137
+ this.updateModel()
138
+
139
+ this.useSaveOnSort && this.replace()
136
140
  },
137
141
 
138
- setSortedValue (value) {
139
- this.sortedList = extend(true, [], value || this.list)
140
- this.updateSortedModel()
142
+ setSortedValue () {
143
+ this.sortedList = extend(true, [], this.modelValue)
141
144
  },
142
145
 
143
- updateSortedModel () {
144
- return this.$emit('update:sorted', this.sortedList)
146
+ updateModel () {
147
+ this.$emit('update:modelValue', this.sortedList)
145
148
  }
146
149
  }
147
150
  }
@@ -9,21 +9,16 @@ props:
9
9
  required: true
10
10
  type: String
11
11
 
12
- list:
13
- desc: Lista que vai ser reordenada.
14
- default: []
15
- type: Array
16
-
17
12
  sortable-options:
18
13
  desc: Opções do "sortablejs" (https://github.com/SortableJS/Sortable#options).
19
14
  default: { animation: 500 }
20
15
  type: Object
21
16
 
22
- sorted:
23
- desc: Model da lista reordenada
17
+ model-value:
18
+ desc: Model do componente onde será fornecido a lista, e ele será responsável pela ordenação.
24
19
  default: []
25
20
  type: Array
26
- examples: [v-model:sorted="fields"]
21
+ examples: [v-model="fields"]
27
22
  model: true
28
23
 
29
24
  tag:
@@ -35,6 +30,11 @@ props:
35
30
  desc: Parâmetro enviado para a action "replace".
36
31
  type: String
37
32
 
33
+ use-save-on-sort:
34
+ desc: Controla se deve bater a API para salvar após fazer uma ordenação.
35
+ type: Boolean
36
+ default: true
37
+
38
38
  slots:
39
39
  default:
40
40
  desc: Slot para adicionar os items que serão reordenados.
@@ -57,9 +57,9 @@ events:
57
57
  desc: fields.
58
58
  type: Object
59
59
 
60
- '@update:sorted -> function(value)':
61
- desc: Dispara no created e toda vez que a prop "list" muda, usado para o v-model:sorted.
60
+ '@update:model-value -> function(values)':
61
+ desc: Dispara quando o model-value altera, após acontecer uma ordenação.
62
62
  params:
63
- value:
64
- desc: Lista contendo nova ordenação.
63
+ values:
64
+ desc: Novo valor do model.
65
65
  type: Array
@@ -5,7 +5,7 @@
5
5
  <slot>{{ text }}</slot>
6
6
  </div>
7
7
 
8
- <div v-if="isTruncated" class="cursor-pointer text-primary" @click.stop="toggle">
8
+ <div v-if="isTruncated" class="cursor-pointer text-primary" @click.stop.prevent="toggle">
9
9
  {{ seeMoreLabel }}
10
10
  </div>
11
11
  </div>
@@ -9,7 +9,7 @@
9
9
 
10
10
  <span v-if="hasMenuButton(node)" class="q-ml-sm">
11
11
  <!-- TODO: rever para o uso QasActionsMenu -->
12
- <qas-btn color="grey-9" icon="sym_r_more_vert" variant="tertiary" @click.stop>
12
+ <qas-btn color="grey-9" icon="sym_r_more_vert" variant="tertiary" @click.stop.prevent>
13
13
  <q-menu auto-close>
14
14
  <q-list separator>
15
15
  <q-item v-if="useAddButton" v-ripple class="qas-tree-generator__item" clickable @click="handleTreeFormDialog(node, true, tree)">
@@ -1,13 +1,21 @@
1
1
  <template>
2
2
  <div class="q-mb-xl qas-welcome text-left">
3
- <h3 class="text-grey-9 text-h3">
4
- {{ welcomeMessage }}<span v-if="firstName">, {{ firstName }}</span>
5
- </h3>
3
+ <div class="items-center justify-between row">
4
+ <div>
5
+ <h3 class="text-grey-9 text-h3">
6
+ {{ welcomeMessage }}<span v-if="firstName">, {{ firstName }}</span>
7
+ </h3>
6
8
 
7
- <div class="text-caption text-grey-8">{{ currentDay }}</div>
9
+ <div class="text-caption text-grey-8">{{ currentDay }}</div>
10
+ </div>
11
+
12
+ <slot name="actions">
13
+ <qas-actions-menu v-if="hasActionsMenuProps" v-bind="actionsMenuProps" />
14
+ </slot>
15
+ </div>
8
16
 
9
17
  <div v-if="hasShortcuts">
10
- <div class="q-mb-md q-mt-md text-grey-9 text-subtitle2">Atalhos</div>
18
+ <qas-label class="q-mt-lg" label="Atalhos" />
11
19
 
12
20
  <div class="qas-welcome__container">
13
21
  <div ref="scrollArea" class="row" :class="contentClasses">
@@ -34,6 +42,11 @@ export default {
34
42
  },
35
43
 
36
44
  props: {
45
+ actionsMenuProps: {
46
+ default: () => ({}),
47
+ type: Object
48
+ },
49
+
37
50
  name: {
38
51
  default: '',
39
52
  type: String
@@ -68,6 +81,10 @@ export default {
68
81
  return this.name.split(' ')?.[0]
69
82
  },
70
83
 
84
+ hasActionsMenuProps () {
85
+ return !!Object.keys(this.actionsMenuProps).length
86
+ },
87
+
71
88
  hasShortcuts () {
72
89
  return !!this.shortcuts.length
73
90
  },
@@ -4,6 +4,11 @@ meta:
4
4
  desc: Componente de boas-vindas para ser usado na Home dos sistemas.
5
5
 
6
6
  props:
7
+ actions-menu-props:
8
+ desc: Propriedades repassadas para o QasActionsMenu.
9
+ default: {}
10
+ type: Object
11
+
7
12
  name:
8
13
  desc: Nome do usuário a ser mostrado na tela.
9
14
  type: String
@@ -12,3 +17,7 @@ props:
12
17
  desc: Lista de cards de atalhos.
13
18
  default: []
14
19
  type: Array
20
+
21
+ slots:
22
+ actions:
23
+ desc: Slot para substituir o QasActionsMenu.
@@ -0,0 +1,28 @@
1
+ @keyframes rotation {
2
+ from {
3
+ transform: rotate(0deg);
4
+ }
5
+
6
+ to {
7
+ transform: rotate(359deg);
8
+ }
9
+ }
10
+
11
+ .icons-is-loading {
12
+ .material-symbols-rounded {
13
+ position: relative;
14
+ color: transparent;
15
+
16
+ &::before {
17
+ content: '';
18
+ background-image: url('~@bildvitta/quasar-ui-asteroid/src/assets/icon-loading.svg');
19
+ background-size: contain;
20
+ background-repeat: no-repeat;
21
+ background-position: center center;
22
+ animation: rotation 1s infinite linear;
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ }
27
+ }
28
+ }
@@ -0,0 +1 @@
1
+ @import './font-face';
@@ -39,7 +39,7 @@
39
39
  position: relative;
40
40
 
41
41
  &:disabled {
42
- color: $grey-8 !important;
42
+ color: $grey-6 !important;
43
43
  }
44
44
  }
45
45
 
@@ -58,7 +58,7 @@
58
58
  padding: 0 !important;
59
59
 
60
60
  &:disabled {
61
- color: $grey-8 !important;
61
+ color: $grey-6 !important;
62
62
  }
63
63
 
64
64
  &-grey-9 {
@@ -0,0 +1,3 @@
1
+ export default function getRequiredLabel ({ label, required }) {
2
+ return required ? `${label}*` : label
3
+ }
@@ -11,6 +11,7 @@ export { default as filterObjectToArray } from './filter-object-to-array.js'
11
11
  export { default as findChildrenByKey } from './find-children-by-key.js'
12
12
  export { default as getGreatestCommonDivisor } from './get-greatest-common-divisor.js'
13
13
  export { default as getNormalizedOptions } from './get-normalized-options.js'
14
+ export { default as getRequiredLabel } from './get-required-label.js'
14
15
  export { default as getSlotChildrenText } from './get-slot-children-text.js'
15
16
  export { default as handleProcess } from './handle-process.js'
16
17
  export { default as isEmpty } from './is-empty.js'
package/src/index.scss CHANGED
@@ -19,6 +19,9 @@ $background-color: var(--qas-background-color);
19
19
  $generic-border-radius: var(--qas-generic-border-radius);
20
20
  $border-grey: var(--qas-border-grey);
21
21
 
22
+ // base
23
+ @import './css/base/index';
24
+
22
25
  // variables
23
26
  @import './css/variables/index';
24
27
 
@@ -92,7 +92,7 @@ export default {
92
92
  watch: {
93
93
  'lazyLoadingProps.params': {
94
94
  handler (newParams, oldParams) {
95
- if (isEqual(newParams, oldParams)) return
95
+ if (!this.useLazyLoading || isEqual(newParams, oldParams)) return
96
96
 
97
97
  this.mx_cachedOptions = []
98
98
 
@@ -20,11 +20,20 @@ export default function (config = {}) {
20
20
  const { entity, id, url } = deleteActionParams
21
21
 
22
22
  const defaultDialogProps = {
23
- card: { description: 'Tem certeza que deseja excluir este item?' },
23
+ ...dialogProps,
24
24
 
25
- ok: { label: 'Excluir', onClick: () => destroy.call(this) },
25
+ card: {
26
+ description: 'Tem certeza que deseja excluir este item?',
26
27
 
27
- ...dialogProps
28
+ ...dialogProps.card
29
+ },
30
+
31
+ ok: {
32
+ label: 'Excluir',
33
+ onClick: () => destroy.call(this),
34
+
35
+ ...dialogProps.ok
36
+ }
28
37
  }
29
38
 
30
39
  const defaultNotifyMessages = {