@bildvitta/quasar-ui-asteroid 2.12.1 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
- "version": "2.12.1",
3
+ "version": "2.13.0",
4
4
  "description": "",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -58,6 +58,7 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@quasar/extras": "^1.9.14",
61
+ "autonumeric": "^4.6.0",
61
62
  "axios": "^0.21.1",
62
63
  "date-fns": "^2.16.1",
63
64
  "fuse.js": "^3.4.6",
@@ -0,0 +1 @@
1
+ <svg width="126" height="26" fill="none" xmlns="http://www.w3.org/2000/svg"><g opacity=".3"><g clip-path="url(#a)"><path d="M6.829 10.909c.02-2.295.059-4.6.119-6.895C9.197 2.653 11.41 1.3 13.58 0c2.172 1.301 4.393 2.653 6.634 4.014.07 2.295.11 4.6.12 6.895a342.175 342.175 0 0 0 6.048 3.417c-.02 2.504-.1 5.017-.238 7.521A575.699 575.699 0 0 0 19.392 26a404.892 404.892 0 0 1-5.81-3.388A525.05 525.05 0 0 1 7.77 26a574.702 574.702 0 0 0-6.753-4.153 158.72 158.72 0 0 1-.238-7.52 381.833 381.833 0 0 0 6.049-3.418Zm6.752-9.24c-1.487.884-2.994 1.788-4.521 2.702 1.487.855 2.994 1.73 4.521 2.613a830.152 830.152 0 0 1 4.522-2.613c-1.527-.904-3.034-1.818-4.522-2.702Zm.714 6.577v5.295c1.537-.884 3.064-1.768 4.591-2.642-.01-1.759-.03-3.507-.06-5.266-1.487.855-3.004 1.729-4.53 2.613Zm5.87 15.658a402.133 402.133 0 0 1 4.602-2.792c.079-1.719.128-3.438.158-5.156-1.547.884-3.084 1.788-4.62 2.692-.04 1.749-.08 3.507-.14 5.256Zm4.046-9.16c-1.517-.845-3.044-1.72-4.571-2.593a767.782 767.782 0 0 0-4.601 2.652c1.527.884 3.044 1.759 4.551 2.613 1.547-.894 3.084-1.788 4.621-2.672Zm-15.806 9.21c1.468-.835 2.955-1.71 4.462-2.594 0-1.768-.01-3.546-.01-5.315a577.521 577.521 0 0 1-4.56 2.623c.029 1.758.059 3.527.108 5.285Zm3.719-9.15c-1.537-.885-3.064-1.78-4.601-2.653a310.65 310.65 0 0 1-4.572 2.593c1.537.874 3.084 1.768 4.621 2.672a573.757 573.757 0 0 0 4.552-2.613Z" fill="#00314D"/></g><path d="m47.676 21.17-.022-10.315-5.113 8.536h-1.29l-5.112-8.403V21.17h-2.756V5.61h2.378l6.18 10.314L48.01 5.61h2.378l.022 15.56h-2.734ZM58.193 21.325c-1.2 0-2.282-.26-3.245-.778a5.774 5.774 0 0 1-2.268-2.156c-.533-.934-.8-1.986-.8-3.157 0-1.17.267-2.215.8-3.134a5.774 5.774 0 0 1 2.267-2.156c.964-.52 2.045-.778 3.246-.778 1.215 0 2.304.259 3.268.778a5.619 5.619 0 0 1 2.245 2.156c.548.919.822 1.963.822 3.134 0 1.17-.274 2.223-.822 3.157a5.62 5.62 0 0 1-2.245 2.156c-.964.518-2.053.778-3.268.778Zm0-2.379c1.023 0 1.867-.34 2.534-1.022.667-.682 1-1.578 1-2.69 0-1.111-.333-2.008-1-2.69-.667-.681-1.511-1.022-2.534-1.022s-1.867.34-2.534 1.022c-.652.682-.978 1.579-.978 2.69 0 1.112.326 2.008.978 2.69.667.681 1.511 1.022 2.534 1.022ZM78.513 4.675V21.17h-2.667v-1.534c-.46.563-1.03.986-1.712 1.267-.667.282-1.408.423-2.223.423-1.14 0-2.17-.252-3.09-.756a5.47 5.47 0 0 1-2.133-2.134c-.52-.934-.779-2-.779-3.2 0-1.201.26-2.26.778-3.18a5.471 5.471 0 0 1 2.135-2.134c.918-.504 1.948-.755 3.09-.755.785 0 1.503.133 2.155.4a4.337 4.337 0 0 1 1.668 1.2v-6.09h2.778Zm-6.268 14.271c.667 0 1.267-.148 1.8-.444a3.372 3.372 0 0 0 1.267-1.312c.312-.563.467-1.215.467-1.956 0-.74-.155-1.393-.467-1.956a3.217 3.217 0 0 0-1.267-1.29 3.507 3.507 0 0 0-1.8-.466c-.667 0-1.267.155-1.8.467a3.217 3.217 0 0 0-1.268 1.289c-.311.563-.467 1.215-.467 1.956 0 .741.156 1.393.467 1.956.311.563.734 1 1.267 1.312a3.644 3.644 0 0 0 1.8.444ZM91.854 9.299v11.87H89.21v-1.511c-.444.533-1 .948-1.667 1.244a5.487 5.487 0 0 1-2.156.423c-1.586 0-2.838-.437-3.757-1.312-.904-.889-1.356-2.2-1.356-3.934v-6.78h2.779V15.7c0 1.067.237 1.867.711 2.4.49.52 1.178.779 2.067.779.993 0 1.779-.304 2.357-.912.592-.622.889-1.511.889-2.667V9.299h2.778ZM93.805 4.675h2.78V21.17h-2.78V4.675ZM103.773 9.166c1.749 0 3.083.422 4.002 1.267.933.83 1.4 2.09 1.4 3.778v6.958h-2.623v-1.445c-.341.519-.83.92-1.467 1.2-.622.267-1.378.4-2.267.4-.89 0-1.668-.147-2.334-.444-.667-.311-1.186-.733-1.556-1.267a3.317 3.317 0 0 1-.534-1.845c0-1.067.393-1.919 1.178-2.556.8-.652 2.053-.978 3.757-.978h3.067v-.178c0-.83-.252-1.467-.755-1.912-.489-.444-1.223-.667-2.201-.667-.667 0-1.326.104-1.978.312-.638.207-1.179.496-1.623.867l-1.09-2.023c.623-.475 1.371-.838 2.246-1.09a9.984 9.984 0 0 1 2.778-.377Zm-.377 10.136c.696 0 1.311-.156 1.845-.467a2.638 2.638 0 0 0 1.155-1.378v-1.378h-2.867c-1.601 0-2.401.526-2.401 1.578 0 .504.2.904.6 1.2.4.297.956.445 1.668.445ZM113.997 11.033c.8-1.245 2.208-1.867 4.224-1.867v2.645a3.532 3.532 0 0 0-.645-.067c-1.082 0-1.927.319-2.534.956-.608.622-.912 1.526-.912 2.712v5.757h-2.778V9.3h2.645v1.734Z" fill="#00314D"/></g><defs><clipPath id="a"><path fill="#fff" transform="matrix(-1 0 0 1 26.383 0)" d="M0 0h25.603v26H0z"/></clipPath></defs></svg>
@@ -17,10 +17,6 @@ export default {
17
17
  },
18
18
 
19
19
  argTypes: {
20
- apps: {
21
- description: 'List of apps with `href`, `image` and `label`. Used by QasAppsMenu.'
22
- },
23
-
24
20
  brand: {
25
21
  description: 'Brand image path.'
26
22
  },
@@ -1,82 +1,77 @@
1
1
  <template>
2
- <q-toolbar class="qas-toolbar">
3
- <q-ajax-bar color="white" position="top" size="2px" />
2
+ <q-header v-bind="$attrs" class="bg-white shadow-primary" height-hint="70" v-on="$listeners">
3
+ <q-toolbar class="qas-toolbar" color="bg-white">
4
+ <q-ajax-bar color="white" position="top" size="2px" />
4
5
 
5
- <q-btn dense flat icon="o_menu" round @click="toggleMenuDrawer" />
6
+ <q-btn color="grey-7" dense flat icon="o_menu" round @click="toggleMenuDrawer" />
6
7
 
7
- <q-toolbar-title class="flex">
8
- <div class="cursor-pointer" @click="goToRoot">
9
- <img v-if="brand" :alt="title" class="q-mr-sm qas-toolbar__brand" :src="brand">
10
- <span v-if="title" class="text-bold text-primary-contrast text-subtitle1 text-uppercase">{{ title }}</span>
11
- <q-badge v-if="hasDevelopmentBadge" align="middle" class="q-ml-sm" color="negative" :label="developmentBadgeLabel" />
12
- </div>
13
- </q-toolbar-title>
8
+ <q-toolbar-title class="flex">
9
+ <div class="cursor-pointer" @click="goToRoot">
10
+ <img v-if="brand" :alt="title" class="q-mr-sm qas-toolbar__brand" :src="brand">
11
+ <span v-if="showTitle" class="text-bold text-grey-9 text-subtitle1 text-uppercase">{{ title }}</span>
12
+ <q-badge v-if="hasDevelopmentBadge" align="middle" class="q-ml-sm" color="negative" :label="developmentBadgeLabel" />
13
+ </div>
14
+ </q-toolbar-title>
14
15
 
15
- <!-- TODO: Notificações. -->
16
- <div v-if="hasNotifications" class="q-mr-md">
17
- <q-btn class="q-mr-md" dense icon="o_notifications" round unelevated>
18
- <q-badge v-if="notifications" color="red" floating>{{ notifications.count }}</q-badge>
19
- </q-btn>
20
- </div>
16
+ <!-- TODO: Notificações. -->
17
+ <div v-if="hasNotifications" class="q-mr-md">
18
+ <q-btn class="q-mr-md" dense icon="o_notifications" round unelevated>
19
+ <q-badge v-if="notifications" color="red" floating>{{ notifications.count }}</q-badge>
20
+ </q-btn>
21
+ </div>
21
22
 
22
- <qas-apps-menu v-if="hasApps" :apps="apps" class="q-mr-md" />
23
+ <div class="items-center no-wrap q-gutter-md row">
24
+ <slot name="tools" />
23
25
 
24
- <div class="items-center no-wrap q-gutter-md row">
25
- <slot name="tools" />
26
+ <div v-if="isAuth" class="cursor-pointer items-center q-mr-sm qas-toolbar__user rounded-borders row text-grey-9" :title="user.name || user.givenName">
27
+ <qas-avatar class="rounded-borders-left" color="white" dark :image="user.photo" rounded size="42px" text-color="primary" :title="user.name || user.givenName" />
26
28
 
27
- <div v-if="isAuth" class="cursor-pointer items-center q-mr-sm qas-toolbar__user rounded-borders row" :title="user.name || user.givenName">
28
- <qas-avatar class="rounded-borders-left" color="white" dark :image="user.photo" rounded size="42px" text-color="primary" :title="user.name || user.givenName" />
29
+ <div class="q-px-sm qas-toolbar__user-data qs-lh-lg text-caption">
30
+ <div class="ellipsis">{{ user.name || user.givenName }}</div>
31
+ <div class="ellipsis text-bold">{{ user.email }}</div>
32
+ </div>
29
33
 
30
- <div class="q-px-sm qas-toolbar__user-data qs-lh-lg text-caption">
31
- <div class="ellipsis">{{ user.name || user.givenName }}</div>
32
- <div class="ellipsis text-bold">{{ user.email }}</div>
33
- </div>
34
+ <q-menu anchor="bottom end" content-class="shadow-primary" max-height="400px" :offset="[0, 5]" self="top end">
35
+ <div class="qas-toolbar__user-menu">
36
+ <div class="q-pa-lg text-center">
37
+ <button class="unset" @click="goToProfile">
38
+ <qas-avatar :image="user.photo" size="145px" :title="user.name || user.givenName" />
39
+ </button>
34
40
 
35
- <q-menu anchor="bottom end" content-class="shadow-primary" max-height="400px" :offset="[0, 5]" self="top end">
36
- <div class="qas-toolbar__user-menu">
37
- <div class="q-pa-lg text-center">
38
- <button class="unset" @click="goToProfile">
39
- <qas-avatar :image="user.photo" size="145px" :title="user.name || user.givenName" />
40
- </button>
41
+ <div class="ellipsis q-mt-lg qs-lh-sm text-bold text-subtitle1">{{ user.name || user.givenName }}</div>
42
+ <div class="ellipsis q-mt-xs text-caption">{{ user.email }}</div>
41
43
 
42
- <div class="ellipsis q-mt-lg qs-lh-sm text-bold text-subtitle1">{{ user.name || user.givenName }}</div>
43
- <div class="ellipsis q-mt-xs text-caption">{{ user.email }}</div>
44
+ <div class="q-mt-sm">
45
+ <qas-btn flat icon="o_edit" label="Editar" :to="user.to" />
46
+ </div>
44
47
 
45
- <div class="q-mt-sm">
46
- <qas-btn flat icon="o_edit" label="Editar" :to="user.to" />
47
- </div>
48
+ <div class="q-mt-sm">
49
+ <qas-btn v-close-popup class="q-px-lg q-py-xs" dense icon="o_exit_to_app" label="Sair" outline @click="signOut" />
50
+ </div>
48
51
 
49
- <div class="q-mt-sm">
50
- <qas-btn v-close-popup class="q-px-lg q-py-xs" dense icon="o_exit_to_app" label="Sair" outline @click="signOut" />
52
+ <slot name="user" :user="user" />
51
53
  </div>
52
-
53
- <slot name="user" :user="user" />
54
54
  </div>
55
- </div>
56
- </q-menu>
55
+ </q-menu>
56
+ </div>
57
57
  </div>
58
- </div>
59
- </q-toolbar>
58
+ </q-toolbar>
59
+ </q-header>
60
60
  </template>
61
61
 
62
62
  <script>
63
- import QasAppsMenu from '../apps-menu/QasAppsMenu'
64
63
  import QasAvatar from '../avatar/QasAvatar'
65
64
  import QasBtn from '../btn/QasBtn'
66
65
 
67
66
  export default {
67
+ name: 'QasAppBar',
68
+
68
69
  components: {
69
- QasAppsMenu,
70
70
  QasAvatar,
71
71
  QasBtn
72
72
  },
73
73
 
74
74
  props: {
75
- apps: {
76
- default: () => [],
77
- type: Array
78
- },
79
-
80
75
  brand: {
81
76
  default: '',
82
77
  type: String
@@ -128,16 +123,16 @@ export default {
128
123
  return current ? hosts[current] : ''
129
124
  },
130
125
 
131
- hasApps () {
132
- return !!this.apps.length
133
- },
134
-
135
126
  hasDevelopmentBadge () {
136
127
  return !!this.developmentBadgeLabel
137
128
  },
138
129
 
139
130
  hasNotifications () {
140
131
  return !!Object.keys(this.notifications).length
132
+ },
133
+
134
+ showTitle () {
135
+ return this.title && !this.brand
141
136
  }
142
137
  },
143
138
 
@@ -173,7 +168,7 @@ export default {
173
168
  }
174
169
 
175
170
  &__user {
176
- background-color: rgba(white, 0.1);
171
+ background-color: var(--qas-background-color);
177
172
  transition: background-color $generic-hover-transition;
178
173
 
179
174
  &:focus,
@@ -1,28 +1,44 @@
1
1
  <template>
2
- <q-drawer v-model="model" content-class="bg-primary-contrast" :mini="miniMode" :width="230" @before-hide="beforeHide">
3
- <q-list class="text-primary" padding>
4
- <div v-for="(header, index) in items" :key="index">
5
- <q-expansion-item v-if="hasChildren(header)" :active-class="activeSecondaryItemClasses" :default-opened="shouldExpand(header)" expand-icon="o_keyboard_arrow_down" expand-separator :icon="header.icon" :label="header.label" :to="header.to">
6
- <q-item v-for="(item, itemIndex) in header.children" :key="itemIndex" v-ripple :active-class="activeItemClasses" clickable :to="item.to">
7
- <q-item-section v-if="item.icon" avatar>
8
- <q-icon :name="item.icon" />
9
- </q-item-section>
10
- <q-item-section>
11
- <q-item-label>{{ item.label }}</q-item-label>
12
- </q-item-section>
13
- </q-item>
14
- </q-expansion-item>
15
-
16
- <q-item v-else :key="index" v-ripple :active-class="activeItemClasses" clickable :to="header.to">
17
- <q-item-section v-if="header.icon" avatar>
18
- <q-icon :name="header.icon" />
19
- </q-item-section>
20
- <q-item-section>
21
- <q-item-label>{{ header.label }}</q-item-label>
22
- </q-item-section>
23
- </q-item>
2
+ <q-drawer v-model="model" class="qas-app-menu" :mini="miniMode" :width="230" v-on="$listeners" @before-hide="beforeHide" @mini-state="setMiniState">
3
+ <div class="column flex full-height justify-between no-wrap overflow-x-hidden">
4
+ <div>
5
+ <div v-if="displayModuleSection" class="q-ma-md">
6
+ <div class="q-mb-sm text-caption text-grey-7 text-weight-medium">
7
+ Você está no modulo:
8
+ </div>
9
+
10
+ <qas-select v-model="module" :options="modules" @input="redirectHandler(currentModelOption)" />
11
+ </div>
12
+
13
+ <q-list class="text-grey-9 text-weight-medium">
14
+ <template v-for="(header, index) in items">
15
+ <q-expansion-item v-if="hasChildren(header)" :key="header.label" :ref="`item-${index}`" :default-opened="shouldExpand(header)" expand-icon="o_keyboard_arrow_down" expand-separator group="item" :icon="header.icon" :label="header.label" :to="header.to" @click="toggleItem(index)" :active-class="activeItemClassesSecondary">
16
+ <q-item v-for="(item, itemIndex) in header.children" :key="itemIndex" v-ripple :active-class="activeItemClasses" clickable :to="item.to">
17
+ <q-item-section v-if="item.icon" avatar>
18
+ <q-icon :name="item.icon" />
19
+ </q-item-section>
20
+ <q-item-section>
21
+ <q-item-label>{{ item.label }}</q-item-label>
22
+ </q-item-section>
23
+ </q-item>
24
+ </q-expansion-item>
25
+
26
+ <q-item v-else :key="index" v-ripple :active-class="activeItemClasses" clickable :to="header.to">
27
+ <q-item-section v-if="header.icon" avatar>
28
+ <q-icon :name="header.icon" />
29
+ </q-item-section>
30
+ <q-item-section>
31
+ <q-item-label>{{ header.label }}</q-item-label>
32
+ </q-item-section>
33
+ </q-item>
34
+ </template>
35
+ </q-list>
24
36
  </div>
25
- </q-list>
37
+
38
+ <div class="q-mx-md">
39
+ <img v-if="!isMini" alt="modular logo" class="block q-mb-md q-mx-auto" src="../../assets/logo-modular.svg">
40
+ </div>
41
+ </div>
26
42
  </q-drawer>
27
43
  </template>
28
44
 
@@ -30,6 +46,8 @@
30
46
  import { screenMixin } from '../../mixins'
31
47
 
32
48
  export default {
49
+ name: 'QasAppMenu',
50
+
33
51
  mixins: [screenMixin],
34
52
 
35
53
  props: {
@@ -46,22 +64,34 @@ export default {
46
64
  value: {
47
65
  default: true,
48
66
  type: Boolean
67
+ },
68
+
69
+ modules: {
70
+ default: () => [],
71
+ type: Array
72
+ },
73
+
74
+ currentModule: {
75
+ default: '',
76
+ type: String
49
77
  }
50
78
  },
51
79
 
52
80
  data () {
53
81
  return {
54
- miniMode: false
82
+ miniMode: false,
83
+ module: '',
84
+ isMini: false
55
85
  }
56
86
  },
57
87
 
58
88
  computed: {
59
89
  activeItemClasses () {
60
- return 'bg-primary text-primary-contrast'
90
+ return 'bg-primary-contrast text-primary text-weight-bold'
61
91
  },
62
92
 
63
- activeSecondaryItemClasses () {
64
- return 'active bg-secondary-contrast text-primary-contrast'
93
+ activeItemClassesSecondary () {
94
+ return 'text-primary bg-secondary-contrast'
65
95
  },
66
96
 
67
97
  model: {
@@ -72,6 +102,23 @@ export default {
72
102
  set (value) {
73
103
  return this.$emit('input', value)
74
104
  }
105
+ },
106
+
107
+ currentModelOption () {
108
+ return this.modules.find(module => module?.value === this.module)
109
+ },
110
+
111
+ displayModuleSection () {
112
+ return !this.isMini && this.modules.length
113
+ }
114
+ },
115
+
116
+ watch: {
117
+ currentModule: {
118
+ handler (value) {
119
+ this.module = value
120
+ },
121
+ immediate: true
75
122
  }
76
123
  },
77
124
 
@@ -81,7 +128,7 @@ export default {
81
128
  },
82
129
 
83
130
  shouldExpand ({ children, to }) {
84
- return children?.length && this.$route.matched.some(item => item.path === to.path)
131
+ return children?.length && this.$route.matched.some(item => item?.path === to?.path)
85
132
  },
86
133
 
87
134
  beforeHide () {
@@ -89,21 +136,35 @@ export default {
89
136
  this.model = true
90
137
  this.miniMode = !this.miniMode
91
138
  }
139
+ },
140
+
141
+ setMiniState (value) {
142
+ this.isMini = value
143
+ },
144
+
145
+ redirectHandler ({ path }) {
146
+ if (!path.includes(window.location.host)) {
147
+ window.location.href = path
148
+ }
149
+ },
150
+
151
+ toggleItem (index) {
152
+ const component = this.getComponent(index)
153
+
154
+ component?.to && this.isMini && component.toggle()
155
+ },
156
+
157
+ getComponent (index) {
158
+ return this.$refs[`item-${index}`]?.[0]
92
159
  }
93
160
  }
94
161
  }
95
162
  </script>
96
163
 
97
164
  <style lang="scss">
98
- .q-expansion-item {
99
- .active .q-expansion-item__toggle-icon {
100
- color: white !important;
101
- opacity: 1;
102
- }
103
-
104
- .q-expansion-item__toggle-icon {
105
- color: $primary;
106
- opacity: 0.2;
165
+ .qas-app-menu {
166
+ .q-expansion-item--expanded .q-item:not(&--active.q-item) {
167
+ background-color: $grey-1;
107
168
  }
108
169
  }
109
170
  </style>
@@ -12,8 +12,8 @@
12
12
  <script>
13
13
  import QasCheckboxGroup from '../checkbox-group/QasCheckboxGroup.vue'
14
14
  import QasDateTimeInput from '../date-time-input/QasDateTimeInput.vue'
15
- import QasDecimalInput from '../decimal-input/QasDecimalInput.vue'
16
15
  import QasInput from '../input/QasInput.vue'
16
+ import QasNumericInput from '../numeric-input/QasNumericInput.vue'
17
17
  import QasPasswordInput from '../password-input/QasPasswordInput.vue'
18
18
  import QasUploader from '../uploader/QasUploader.vue'
19
19
  import QasSignatureUploader from '../signature-uploader/QasSignatureUploader.vue'
@@ -30,8 +30,8 @@ export default {
30
30
  components: {
31
31
  QasCheckboxGroup,
32
32
  QasDateTimeInput,
33
- QasDecimalInput,
34
33
  QasInput,
34
+ QasNumericInput,
35
35
  QasPasswordInput,
36
36
  QasUploader,
37
37
  QasSignatureUploader
@@ -96,8 +96,8 @@ export default {
96
96
  gmt
97
97
  }
98
98
 
99
+ const numericInput = { is: 'qas-numeric-input', ...input }
99
100
  const datetimeInput = { is: 'qas-date-time-input', gmt, ...input }
100
- const decimalInput = { is: 'qas-decimal-input', comma: true, fillMask: '0', reverseFillMask: true, ...input }
101
101
 
102
102
  // It'll generate a list of acceptable files extensions.
103
103
  const accept = extensions && extensions.length ? extensions.map(extension => `.${extension}`).join(',') : ''
@@ -121,9 +121,9 @@ export default {
121
121
  email: { is: 'q-input', type, ...input },
122
122
  password: { is: 'qas-password-input', type, pattern, hideStrengthChecker: !pattern, ...input },
123
123
 
124
- decimal: { ...decimalInput },
125
- money: { ...decimalInput, prefix: 'R$' },
126
- percent: { ...decimalInput, suffix: '%' },
124
+ decimal: { ...numericInput, mode: 'decimal' },
125
+ money: { ...numericInput, mode: 'money' },
126
+ percent: { ...numericInput, mode: 'percent' },
127
127
 
128
128
  date: { ...datetimeInput, dateOnly: true },
129
129
  datetime: { ...datetimeInput },
@@ -41,7 +41,7 @@
41
41
  </div>
42
42
 
43
43
  <div v-if="badges && hasActiveFilters" class="q-mt-md">
44
- <q-chip v-for="(filterItem, key) in activeFilters" :key="key" color="grey-4" dense removable size="md" text-color="grey-8" @remove="removeFilter(filterItem)">{{ filterItem.label }} = "{{ filterItem.value }}"</q-chip>
44
+ <q-chip v-for="(filterItem, key) in activeFilters" :key="key" color="grey-4" dense removable size="md" text-color="grey-8" @remove="removeFilter(filterItem)">{{ filterItem.label }} = "{{ getChipValue(filterItem.value) }}"</q-chip>
45
45
  </div>
46
46
 
47
47
  <slot :context="context" :filter="filter" :filters="activeFilters" :removeFilter="removeFilter" />
@@ -122,7 +122,7 @@ export default {
122
122
  const hasField = fields.includes(key)
123
123
 
124
124
  if (hasField) {
125
- const value = humanize(this.fields[key], filters[key])
125
+ const value = humanize(this.fields[key], this.normalizeValues(filters[key], this.fields[key]?.multiple))
126
126
  const { label, name } = this.fields[key]
127
127
 
128
128
  activeFilters[key] = { label, name, value }
@@ -188,7 +188,7 @@ export default {
188
188
 
189
189
  created () {
190
190
  this.fetchFilters()
191
- this.updateValues()
191
+ this.watchOnceFields()
192
192
  },
193
193
 
194
194
  methods: {
@@ -252,6 +252,10 @@ export default {
252
252
  this.$router.push({ query })
253
253
  },
254
254
 
255
+ getChipValue (value) {
256
+ return Array.isArray(value) ? value.join(', ') : value
257
+ },
258
+
255
259
  removeFilter ({ name }) {
256
260
  const query = { ...this.$route.query }
257
261
 
@@ -266,8 +270,23 @@ export default {
266
270
  this.search = search || ''
267
271
 
268
272
  for (const key in filters) {
269
- this.$set(this.filters, key, parseValue(filters[key]))
273
+ this.$set(this.filters, key, parseValue(this.normalizeValues(filters[key], this.fields[key]?.multiple)))
270
274
  }
275
+ },
276
+
277
+ normalizeValues (value, isMultiple) {
278
+ if (Array.isArray(value)) return value
279
+
280
+ return isMultiple ? [value] : value
281
+ },
282
+
283
+ watchOnceFields () {
284
+ const watchOnce = this.$watch('fields', values => {
285
+ if (Object.keys(values).length) {
286
+ this.updateValues()
287
+ watchOnce()
288
+ }
289
+ })
271
290
  }
272
291
  }
273
292
  }
@@ -0,0 +1,106 @@
1
+ import QasLayout from './QasLayout.vue'
2
+
3
+ export default {
4
+ component: QasLayout,
5
+ title: 'Components/Layout',
6
+
7
+ parameters: {
8
+ docs: {
9
+ description: {
10
+ component: 'Implementation of [QLayout](https://quasar.dev/layout/layout#introduction) with [QasAppMenu](http://localhost:6006/?path=/docs/components-appmenu--default) and [QasAppBar](http://localhost:6006/?path=/docs/components-appbar--default).'
11
+ }
12
+ }
13
+ },
14
+
15
+ argTypes: {
16
+ // Props
17
+ appMenuProps: {
18
+ description: '[QasAppMenu props](http://localhost:6006/?path=/docs/components-appmenu--default).'
19
+ },
20
+
21
+ appBarProps: {
22
+ description: '[QasAppBar props](http://localhost:6006/?path=/docs/components-appbar--default).'
23
+ },
24
+
25
+ appMenuEvents: {
26
+ description: '[QasAppMenu events](http://localhost:6006/?path=/docs/components-appmenu--default).'
27
+ },
28
+
29
+ appBarEvents: {
30
+ description: '[QasAppBar events](http://localhost:6006/?path=/docs/components-appbar--default).'
31
+ },
32
+
33
+ value: {
34
+ description: 'Model value for toggle drawer.'
35
+ },
36
+
37
+ // Slots
38
+ 'app-bar': {
39
+ description: 'header slot.'
40
+ },
41
+
42
+ 'app-menu': {
43
+ description: 'left side menu.'
44
+ },
45
+
46
+ default: {
47
+ description: 'page container with router-view.'
48
+ },
49
+
50
+ // events
51
+ input: {
52
+ description: 'input model event for toggle drawer.'
53
+ }
54
+ }
55
+ }
56
+
57
+ const Template = (args, { argTypes }) => ({
58
+ components: { QasLayout },
59
+ props: Object.keys(argTypes),
60
+
61
+ template: '<qas-layout v-bind="$props" />'
62
+ })
63
+
64
+ export const Default = Template.bind({})
65
+
66
+ Default.args = {
67
+ appMenuProps: {
68
+ items: [
69
+ {
70
+ label: 'Dialog',
71
+ icon: 'o_home',
72
+ to: { path: '/dialog-form' }
73
+ },
74
+
75
+ {
76
+ label: 'Teste expansivo',
77
+ icon: 'o_edit'
78
+ }
79
+ ],
80
+
81
+ modules: [
82
+ {
83
+ label: 'Modulo de teste',
84
+ value: 'test',
85
+ path: 'http://localhost:8080'
86
+ },
87
+ {
88
+ label: 'Segundo modulo de teste',
89
+ value: 'test-2',
90
+ path: 'https://google.com'
91
+ }
92
+ ],
93
+
94
+ currentModule: 'test'
95
+ },
96
+
97
+ appBarProps: {
98
+ isAuth: true,
99
+ title: 'Some title',
100
+ user: {
101
+ photo: 'https://www.abc.net.au/cm/lb/6367016/data/alan2c-see-the-person-data.jpg',
102
+ name: 'Eduardo Lima',
103
+ email: 'eduardolima@gmail.com'
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,84 @@
1
+ <template>
2
+ <q-layout view="hHh Lpr lFf">
3
+ <slot name="app-bar">
4
+ <qas-app-bar v-bind="appBarProps" v-on="appBarEvents" @toggle-menu="toggleMenuDrawer" />
5
+ </slot>
6
+
7
+ <slot name="app-menu">
8
+ <qas-app-menu v-model="menuDrawer" v-bind="appMenuProps" v-on="appMenuEvents" />
9
+ </slot>
10
+
11
+ <slot>
12
+ <q-page-container>
13
+ <router-view />
14
+ </q-page-container>
15
+ </slot>
16
+ </q-layout>
17
+ </template>
18
+
19
+ <script>
20
+ import QasAppMenu from '../app-menu/QasAppMenu'
21
+ import QasAppBar from '../app-bar/QasAppBar'
22
+
23
+ export default {
24
+ name: 'QasLayout',
25
+
26
+ components: {
27
+ QasAppMenu,
28
+ QasAppBar
29
+ },
30
+
31
+ props: {
32
+ value: {
33
+ default: true,
34
+ type: Boolean
35
+ },
36
+
37
+ appBarEvents: {
38
+ default: () => ({}),
39
+ type: Object
40
+ },
41
+
42
+ appBarProps: {
43
+ default: () => ({}),
44
+ type: Object
45
+ },
46
+
47
+ appMenuProps: {
48
+ default: () => ({}),
49
+ type: Object
50
+ },
51
+
52
+ appMenuEvents: {
53
+ default: () => ({}),
54
+ type: Object
55
+ }
56
+ },
57
+
58
+ data () {
59
+ return {
60
+ menuDrawer: true
61
+ }
62
+ },
63
+
64
+ watch: {
65
+ $route () {
66
+ console.log('chamado no layout')
67
+ },
68
+
69
+ value: {
70
+ handler (value) {
71
+ this.menuDrawer = value
72
+ },
73
+ immediate: true
74
+ }
75
+ },
76
+
77
+ methods: {
78
+ toggleMenuDrawer () {
79
+ this.menuDrawer = !this.menuDrawer
80
+ this.$emit('input', this.menuDrawer)
81
+ }
82
+ }
83
+ }
84
+ </script>
@@ -1,25 +1,41 @@
1
- import QasDecimalInput from './QasDecimalInput.vue'
1
+ import QasNumericInput from './QasNumericInput.vue'
2
2
 
3
3
  export default {
4
- component: QasDecimalInput,
5
- title: 'Components/DecimalInput',
4
+ component: QasNumericInput,
5
+ title: 'Components/NumericInput',
6
6
 
7
7
  parameters: {
8
8
  docs: {
9
9
  description: {
10
- component: 'Extends [QInput](https://quasar.dev/vue-components/input), but with decimal mask.'
10
+ component: 'Extends [QInput](https://quasar.dev/vue-components/input) with [AutoNumeric](http://autonumeric.org/) plugin.'
11
11
  }
12
12
  }
13
13
  },
14
14
 
15
15
  argTypes: {
16
16
  // Props
17
- comma: {
18
- description: 'Use comma instead of period as decimal separator.'
17
+ allowNegative: {
18
+ description: 'Allow negative values.'
19
19
  },
20
20
 
21
- places: {
22
- description: 'Number of decimal places.'
21
+ allowPositive: {
22
+ description: 'Allow positive values.'
23
+ },
24
+
25
+ autonumericProps: {
26
+ description: '(Autonumeric)[http://autonumeric.org/guide] options.'
27
+ },
28
+
29
+ decimalPlaces: {
30
+ description: 'Decimal places.'
31
+ },
32
+
33
+ mode: {
34
+ description: 'Component mode like integer, decimal, percent, and money.'
35
+ },
36
+
37
+ preset: {
38
+ description: 'Property to configure default nationality of currency.'
23
39
  },
24
40
 
25
41
  value: {
@@ -35,16 +51,12 @@ export default {
35
51
  summary: '{}'
36
52
  }
37
53
  }
38
- },
39
-
40
- mount: {
41
- table: { disable: true }
42
54
  }
43
55
  }
44
56
  }
45
57
 
46
58
  const Template = (args, { argTypes }) => ({
47
- components: { QasDecimalInput },
59
+ components: { QasNumericInput },
48
60
  props: Object.keys(argTypes),
49
61
 
50
62
  data () {
@@ -55,7 +67,7 @@ const Template = (args, { argTypes }) => ({
55
67
 
56
68
  template:
57
69
  `<div>
58
- <qas-decimal-input v-bind="$props" v-model="model" />
70
+ <qas-numeric-input v-bind="$props" v-model="model" />
59
71
  <pre>{{ model }}</pre>
60
72
  </div>`
61
73
  })
@@ -64,19 +76,17 @@ export const Default = Template.bind({})
64
76
 
65
77
  Default.parameters = {
66
78
  docs: {
67
- source: { code: '<qas-decimal-input v-model="model" />' }
79
+ source: { code: '<qas-numeric-input v-model="model" />' }
68
80
  }
69
81
  }
70
82
 
71
83
  export const BrazilianReal = Template.bind({})
72
84
 
73
85
  BrazilianReal.args = {
74
- comma: true,
75
- prefix: 'R$'
76
86
  }
77
87
 
78
88
  BrazilianReal.parameters = {
79
89
  docs: {
80
- source: { code: '<qas-decimal-input v-model="model" comma prefix="R$" />' }
90
+ source: { code: '<qas-numeric-input v-model="model" />' }
81
91
  }
82
92
  }
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <div>
3
+ <q-field v-model="model" v-bind="$attrs">
4
+ <template #control="{ emitValue, floatingLabel, id, value: modelValue }">
5
+ <input v-show="floatingLabel" :id="id" ref="input" class="q-field__input" :model-value="modelValue" @input="emitValue($event.target.value)">
6
+ </template>
7
+ </q-field>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ const defaultModes = {
13
+ integer: ['commaDecimalCharDotSeparator', 'integer'],
14
+ decimal: 'commaDecimalCharDotSeparator',
15
+ percent: 'percentageEU2dec',
16
+ money: 'Brazilian'
17
+ }
18
+
19
+ export default {
20
+ props: {
21
+ allowNegative: {
22
+ default: true,
23
+ type: Boolean
24
+ },
25
+
26
+ allowPositive: {
27
+ default: true,
28
+ type: Boolean
29
+ },
30
+
31
+ autonumericProps: {
32
+ default: () => ({}),
33
+ type: Object
34
+ },
35
+
36
+ decimalPlaces: {
37
+ default: 2,
38
+ type: Number
39
+ },
40
+
41
+ mode: {
42
+ default: 'integer',
43
+ type: String,
44
+ validator: value => ['integer', 'decimal', 'percent', 'money'].includes(value)
45
+ },
46
+
47
+ preset: {
48
+ default: false,
49
+ type: [Boolean, String]
50
+ },
51
+
52
+ value: {
53
+ default: '',
54
+ validator (value) {
55
+ return typeof value === 'number' || typeof value === 'string' || value === '' || value === null
56
+ }
57
+ }
58
+ },
59
+
60
+ data () {
61
+ return {
62
+ autoNumeric: null
63
+ }
64
+ },
65
+
66
+ computed: {
67
+ defaultMode () {
68
+ return defaultModes[this.mode]
69
+ },
70
+
71
+ model: {
72
+ get () {
73
+ return this.value
74
+ },
75
+
76
+ set () {
77
+ this.$emit('input', this.autoNumeric.getNumber())
78
+ }
79
+ }
80
+ },
81
+
82
+ async created () {
83
+ const AutoNumeric = (await import('autonumeric')).default
84
+ const autoNumericPredefinedOptions = AutoNumeric.getPredefinedOptions()
85
+
86
+ let option = this.preset || this.defaultMode
87
+
88
+ if (!Array.isArray(option)) {
89
+ option = [option]
90
+ }
91
+
92
+ const options = {}
93
+
94
+ for (const value of option) {
95
+ Object.assign(options, autoNumericPredefinedOptions[value])
96
+ }
97
+
98
+ if (!this.allowNegative) {
99
+ options.minimumValue = 0
100
+ }
101
+
102
+ if (!this.allowPositive) {
103
+ options.maximumValue = 0
104
+ }
105
+
106
+ if (this.mode !== 'integer') {
107
+ options.decimalPlaces = this.decimalPlaces
108
+ }
109
+
110
+ Object.assign(options, this.autonumericProps)
111
+
112
+ this.$nextTick(() => {
113
+ this.$refs.input.value = this.value
114
+ this.autoNumeric = new AutoNumeric(this.$refs.input, options)
115
+ })
116
+ },
117
+
118
+ beforeDestroy () {
119
+ this.autoNumeric.remove()
120
+ }
121
+ }
122
+ </script>
@@ -26,6 +26,8 @@
26
26
 
27
27
  <script>
28
28
  export default {
29
+ name: 'QasSelect',
30
+
29
31
  props: {
30
32
  fuseOptions: {
31
33
  default: () => ({}),
@@ -96,6 +96,8 @@ function handleMasks (value) {
96
96
 
97
97
  // Labels
98
98
  function humanize (field = {}, value) {
99
+ if (!value) return value
100
+
99
101
  const mappedMasks = handleMasks(value)
100
102
 
101
103
  if (mappedMasks[field.mask]) {
package/src/index.js CHANGED
@@ -14,7 +14,6 @@ import QasCheckboxGroup from './components/checkbox-group/QasCheckboxGroup'
14
14
  import QasCopy from './components/copy/QasCopy'
15
15
  import QasDateTimeInput from './components/date-time-input/QasDateTimeInput'
16
16
  import QasDebugger from './components/debugger/QasDebugger'
17
- import QasDecimalInput from './components/decimal-input/QasDecimalInput'
18
17
  import QasDelete from './components/delete/QasDelete'
19
18
  import QasDialog from './components/dialog/QasDialog'
20
19
  import QasDialogRouter from './components/dialog-router/QasDialogRouter'
@@ -26,10 +25,12 @@ import QasGallery from './components/gallery/QasGallery'
26
25
  import QasGridGenerator from './components/grid-generator/QasGridGenerator'
27
26
  import QasInput from './components/input/QasInput'
28
27
  import QasLabel from './components/label/QasLabel'
28
+ import QasLayout from './components/layout/QasLayout'
29
29
  import QasListItems from './components/list-items/QasListItems'
30
30
  import QasListView from './components/list-view/QasListView'
31
31
  import QasMap from './components/map/QasMap'
32
32
  import QasNestedFields from './components/nested-fields/QasNestedFields'
33
+ import QasNumericInput from './components/numeric-input/QasNumericInput'
33
34
  import QasPageHeader from './components/page-header/QasPageHeader'
34
35
  import QasPasswordInput from './components/password-input/QasPasswordInput'
35
36
  import QasPasswordStrengthChecker from './components/password-strength-checker/QasPasswordStrengthChecker'
@@ -87,7 +88,6 @@ export {
87
88
  QasCopy,
88
89
  QasDateTimeInput,
89
90
  QasDebugger,
90
- QasDecimalInput,
91
91
  QasDelete,
92
92
  QasDialog,
93
93
  QasDialogRouter,
@@ -99,10 +99,12 @@ export {
99
99
  QasGridGenerator,
100
100
  QasInput,
101
101
  QasLabel,
102
+ QasLayout,
102
103
  QasListItems,
103
104
  QasListView,
104
105
  QasMap,
105
106
  QasNestedFields,
107
+ QasNumericInput,
106
108
  QasPageHeader,
107
109
  QasPasswordInput,
108
110
  QasPasswordStrengthChecker,
@@ -146,7 +148,6 @@ export default {
146
148
  QasCopy,
147
149
  QasDateTimeInput,
148
150
  QasDebugger,
149
- QasDecimalInput,
150
151
  QasDelete,
151
152
  QasDialog,
152
153
  QasDialogRouter,
@@ -158,10 +159,12 @@ export default {
158
159
  QasGridGenerator,
159
160
  QasInput,
160
161
  QasLabel,
162
+ QasLayout,
161
163
  QasListItems,
162
164
  QasListView,
163
165
  QasMap,
164
166
  QasNestedFields,
167
+ QasNumericInput,
165
168
  QasPageHeader,
166
169
  QasPasswordInput,
167
170
  QasPasswordStrengthChecker,
@@ -204,7 +207,6 @@ export default {
204
207
  Vue.component('QasCopy', QasCopy)
205
208
  Vue.component('QasDateTimeInput', QasDateTimeInput)
206
209
  Vue.component('QasDebugger', QasDebugger)
207
- Vue.component('QasDecimalInput', QasDecimalInput)
208
210
  Vue.component('QasDelete', QasDelete)
209
211
  Vue.component('QasDialog', QasDialog)
210
212
  Vue.component('QasDialogRouter', QasDialogRouter)
@@ -216,10 +218,12 @@ export default {
216
218
  Vue.component('QasGridGenerator', QasGridGenerator)
217
219
  Vue.component('QasInput', QasInput)
218
220
  Vue.component('QasLabel', QasLabel)
221
+ Vue.component('QasLayout', QasLayout)
219
222
  Vue.component('QasListItems', QasListItems)
220
223
  Vue.component('QasListView', QasListView)
221
224
  Vue.component('QasMap', QasMap)
222
225
  Vue.component('QasNestedFields', QasNestedFields)
226
+ Vue.component('QasNumericInput', QasNumericInput)
223
227
  Vue.component('QasPageHeader', QasPageHeader)
224
228
  Vue.component('QasPasswordInput', QasPasswordInput)
225
229
  Vue.component('QasPasswordStrengthChecker', QasPasswordStrengthChecker)
package/src/index.scss CHANGED
@@ -9,7 +9,7 @@ $secondary-contrast: var(--q-color-secondary-contrast);
9
9
 
10
10
  // Asteroid variables
11
11
  :root {
12
- --qas-background-color: #fcfcff;
12
+ --qas-background-color: #f5f5f5;
13
13
  --qas-generic-border-radius: 8px;
14
14
  }
15
15
 
@@ -1,90 +0,0 @@
1
- <template>
2
- <q-input v-bind="$attrs" fill-mask="0" :mask="mask" reverse-fill-mask :value="inputValue" v-on="events" @input="input" />
3
- </template>
4
-
5
- <script>
6
- export default {
7
- props: {
8
- comma: {
9
- default: false,
10
- type: Boolean
11
- },
12
-
13
- places: {
14
- default: 2,
15
- type: Number
16
- },
17
-
18
- value: {
19
- default: 0,
20
- required: true,
21
- type: Number
22
- }
23
- },
24
-
25
- data () {
26
- return {
27
- inputValue: this.toMask(this.value),
28
- inputedValue: 0
29
- }
30
- },
31
-
32
- computed: {
33
- events () {
34
- const { input, ...events } = this.$listeners
35
- return events
36
- },
37
-
38
- mask () {
39
- return `#${this.separator}${'#'.repeat(this.places)}`
40
- },
41
-
42
- separator () {
43
- return this.comma ? ',' : '.'
44
- }
45
- },
46
-
47
- watch: {
48
- value (current) {
49
- this.inputValue = this.toMask(current)
50
- }
51
- },
52
-
53
- mounted () {
54
- this.$emit('mount', this)
55
- },
56
-
57
- methods: {
58
- blur () {
59
- this.$el.blur()
60
- },
61
-
62
- focus () {
63
- this.$el.focus()
64
- },
65
-
66
- input (value) {
67
- this.inputedValue = this.toDecimal(value)
68
- this.$emit('input', this.inputedValue)
69
- },
70
-
71
- toDecimal (value) {
72
- if (this.comma) {
73
- value = value.replace(',', '.')
74
- }
75
-
76
- return parseFloat(value)
77
- },
78
-
79
- toMask (value) {
80
- value = value.toFixed(this.places)
81
-
82
- if (this.comma) {
83
- value = value.replace('.', ',')
84
- }
85
-
86
- return value
87
- }
88
- }
89
- }
90
- </script>