@mythpe/quasar-ui-qui 0.2.0 → 0.2.2

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": "@mythpe/quasar-ui-qui",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "MyTh Quasar UI Kit App Extension",
5
5
  "author": {
6
6
  "name": "MyTh Ahmed Faiz",
@@ -222,9 +222,11 @@ const {
222
222
  fetchDatatableItems,
223
223
  exportData,
224
224
  openDialogTimeout,
225
+ beforeCloseFilterDialog,
225
226
  openFilterDialog,
226
227
  saveFilterDialog,
227
228
  closeFilterDialog,
229
+ filterDialogModel,
228
230
  onRemoveFilter,
229
231
  updateFilterOptions,
230
232
  openShowDialogNoIndex,
@@ -351,7 +353,7 @@ const onSuccess: SubmissionHandler = async (form) => {
351
353
  } catch (e: any) {
352
354
  const { _message, _errors } = e || {}
353
355
  dialogErrors.value = _errors || {}
354
- scrollToElementFromErrors(_errors, undefined, '.m--datatable__dialog-form-container')
356
+ await scrollToElementFromErrors(_errors, undefined, '.m--datatable__dialog-form-container')
355
357
  _message && alertError(_message)
356
358
  if (_errors) {
357
359
  useFormContext.setErrors(_errors)
@@ -854,13 +856,14 @@ defineExpose({
854
856
  label="myth.datatable.hints.filter"
855
857
  tooltip="myth.datatable.hints.filter"
856
858
  v-bind="{...defaultTopBtnProps,...pluginOptions.dt?.buttons?.filter as any}"
857
- @click="openFilterDialog()"
858
859
  >
859
860
  <MModalMenu
861
+ v-model="filterDialogModel"
860
862
  no-close-btn
861
863
  persistent
862
864
  position="top"
863
865
  v-bind="pluginOptions.dt?.filterDialogProps as any"
866
+ @before-show="beforeCloseFilterDialog"
864
867
  >
865
868
  <q-card
866
869
  :style="$q.screen.gt.sm?`width: ${Math.ceil($q.screen.width/2)}px` : undefined"
@@ -1059,9 +1062,9 @@ defineExpose({
1059
1062
  <span>
1060
1063
  {{ getHeaders.find(e => e.name === filterKey)?.label || __(`attributes.${filterKey}`) }}
1061
1064
  </span>
1062
- <span v-if="typeof filterValue === 'boolean'">: {{
1063
- __(`labels.${filterValue ? 'yes' : 'no'}`)
1064
- }}</span>
1065
+ <span v-if="typeof filterValue === 'boolean'">
1066
+ : {{ __(`labels.${filterValue ? 'yes' : 'no'}`) }}
1067
+ </span>
1065
1068
  <span v-else-if="typeof filterValue === 'string'">: {{ filterValue }}</span>
1066
1069
  <span
1067
1070
  v-else-if="Array.isArray(filterValue) && !quasarHelpers.object(filterValue[0])"
@@ -1072,6 +1075,7 @@ defineExpose({
1072
1075
  <span
1073
1076
  v-else-if="quasarHelpers.object(filterValue) && filterValue.label"
1074
1077
  >: {{ filterValue.label }}</span>
1078
+ <span v-else-if="typeof filterValue === 'object'">:&nbsp;{{ Object.values(filterValue).join(' - ') }}</span>
1075
1079
  </q-chip>
1076
1080
  </MCol>
1077
1081
  </template>
@@ -0,0 +1,289 @@
1
+ <!--
2
+ - MyTh Ahmed Faiz Copyright © 2016-2024 All rights reserved.
3
+ - Email: mythpe@gmail.com
4
+ - Mobile: +966590470092
5
+ - Website: https://www.4myth.com
6
+ - Github: https://github.com/mythpe
7
+ -->
8
+
9
+ <script
10
+ lang="ts"
11
+ setup
12
+ >
13
+
14
+ import { useField } from 'vee-validate'
15
+ import type { MOptionsOptionContext, MOptionsProps as Props } from '../../types'
16
+ import { computed, onMounted, reactive, toValue, useTemplateRef } from 'vue'
17
+ import type { QField, QOptionGroupSlots } from 'quasar'
18
+ import { QOptionGroup } from 'quasar'
19
+ import { useBindInput, useMyth } from '../../composable'
20
+
21
+ interface P {
22
+ name: Props['name'];
23
+ auto?: Props['auto'];
24
+ col?: Props['col'];
25
+ xs?: Props['xs'];
26
+ sm?: Props['sm'];
27
+ md?: Props['md'];
28
+ lg?: Props['lg'];
29
+ xl?: Props['xl'];
30
+ label?: Props['label'];
31
+ caption?: Props['caption'];
32
+ hint?: Props['hint'];
33
+ placeholder?: Props['placeholder'];
34
+ help?: Props['help'];
35
+ required?: Props['required'];
36
+ rules?: Props['rules'];
37
+ disable?: Props['disable'];
38
+ viewMode?: Props['viewMode'];
39
+ viewModeValue?: Props['viewModeValue'];
40
+ topLabel?: Props['topLabel'];
41
+ color?: Props['color'];
42
+ type?: Props['type'];
43
+ keepColor?: Props['keepColor'];
44
+ service?: Props['service'];
45
+ guest?: boolean;
46
+ fullWidth?: Props['fullWidth'];
47
+ fitWidth?: Props['fullWidth'];
48
+ fieldOptions?: Props['fieldOptions'];
49
+ }
50
+
51
+ const props = withDefaults(defineProps<P>(), {
52
+ name: () => '',
53
+ auto: undefined,
54
+ col: undefined,
55
+ xs: undefined,
56
+ sm: undefined,
57
+ md: undefined,
58
+ lg: undefined,
59
+ xl: undefined,
60
+ label: undefined,
61
+ caption: undefined,
62
+ hint: undefined,
63
+ placeholder: undefined,
64
+ help: undefined,
65
+ required: undefined,
66
+ rules: undefined,
67
+ disable: undefined,
68
+ viewMode: !1,
69
+ viewModeValue: undefined,
70
+ topLabel: undefined,
71
+ color: 'primary',
72
+ type: 'radio',
73
+ keepColor: undefined,
74
+ guest: !1,
75
+ service: undefined,
76
+ fullWidth: !1,
77
+ fitWidth: !1,
78
+ fieldOptions: undefined
79
+ })
80
+ defineModel<Props['modelValue']>({ required: !1, default: undefined })
81
+ const loading = defineModel<Props['loading']>('loading', { required: !1, default: !1 })
82
+ const options = defineModel<MOptionsOptionContext[]>('options', { required: !1, default: undefined })
83
+ const helper = useBindInput<P>(() => props, 'options')
84
+ const { getLabel, inputRules, getProp, theme } = helper
85
+ const inputScope = useField<Props['modelValue']>(() => props.name, inputRules, {
86
+ syncVModel: !0,
87
+ label: getLabel,
88
+ ...toValue<any>(props.fieldOptions)
89
+ })
90
+ const { value, errorMessage, handleChange, handleBlur } = inputScope
91
+
92
+ const listeners = {
93
+ blur: (v: any) => handleBlur(v, !0),
94
+ 'update:modelValue': (v: Props['modelValue']) => handleChange(v, !!errorMessage.value)
95
+ }
96
+ const input = useTemplateRef<InstanceType<typeof QField> | InstanceType<typeof QOptionGroup>>('input')
97
+ const scopes = reactive(inputScope)
98
+ defineExpose<typeof scopes & { input: typeof input }>({ input, ...scopes })
99
+ const { alertError, __, props: pluginProps, api } = useMyth()
100
+ const fetchData = async () => {
101
+ if (props.service) {
102
+ const s = props.service
103
+ loading.value = !0
104
+ try {
105
+ let method: any = null
106
+ if (typeof s === 'string' && s.includes('.')) {
107
+ const args = s.split('.')
108
+ do {
109
+ if (!method) {
110
+ method = api.value.services[args.shift() as any]
111
+ }
112
+ method = method[args.shift() as any]
113
+ }
114
+ while (args.length)
115
+ } else {
116
+ method = typeof s === 'function' ? s : (props.guest ? api.value.services[s].staticIndex : api.value.services[s].index)
117
+ }
118
+ if (method != null) {
119
+ const { _data } = await method()
120
+ options.value = _data as any
121
+ }
122
+ } catch (e: any) {
123
+ alertError(e?._message || e?.message || 'Failed to fetch data')
124
+ } finally {
125
+ loading.value = !1
126
+ }
127
+ }
128
+ }
129
+ const getOptions = computed(() => {
130
+ if (props.viewMode) {
131
+ return options.value.filter(e => e.value === value.value)
132
+ }
133
+ return options.value
134
+ })
135
+ onMounted(() => {
136
+ fetchData()
137
+ })
138
+ defineOptions({
139
+ name: 'MOptions',
140
+ inheritAttrs: !1
141
+ })
142
+ </script>
143
+
144
+ <template>
145
+ <MCol
146
+ :auto="auto"
147
+ :class="[$attrs.class,{'m--input__required':inputRules?.required!==undefined,'m--input__error':!!errorMessage,'m--input__view':viewMode}]"
148
+ :col="col"
149
+ :lg="lg"
150
+ :md="md"
151
+ :name="name"
152
+ :sm="sm"
153
+ :xs="xs"
154
+ >
155
+ <slot
156
+ name="top-input"
157
+ v-bind="scopes"
158
+ />
159
+ <slot name="top-label">
160
+ <MInputLabel
161
+ v-if="!!getLabel"
162
+ :field="scopes"
163
+ >
164
+ <template #default>
165
+ <MHelpRow
166
+ v-if="!!help"
167
+ :text="help"
168
+ class="q-ml-lg"
169
+ tooltip
170
+ />
171
+ <template v-if="loading">
172
+ <div class="flex-break" />
173
+ <q-spinner-dots
174
+ class="q-mt-lg q-ml-lg"
175
+ color="primary"
176
+ size="22px"
177
+ />
178
+ </template>
179
+ </template>
180
+ </MInputLabel>
181
+ </slot>
182
+ <slot name="caption">
183
+ <div
184
+ v-if="!!caption"
185
+ class="m--input__caption"
186
+ >
187
+ {{ __(caption) }}
188
+ </div>
189
+ </slot>
190
+ <MTransition>
191
+ <div
192
+ v-if="!!errorMessage"
193
+ class="text-negative text-caption"
194
+ >
195
+ <q-icon
196
+ v-if="!!errorMessage"
197
+ color="negative"
198
+ name="ion-ios-information-circle-outline"
199
+ size="20px"
200
+ />
201
+ {{ errorMessage }}
202
+ </div>
203
+ </MTransition>
204
+ <q-option-group
205
+ ref="input"
206
+ :class="{'m--options': !0, 'm--options__full_width': fullWidth, 'm--options__fit_width': fitWidth }"
207
+ :color="!!errorMessage ? 'negative' : getProp('color')"
208
+ :disable="disable"
209
+ :keep-color="!!errorMessage ? !0 : getProp('keepColor')"
210
+ :option-disable="viewMode ? (v) => v.value !== value : undefined"
211
+ v-bind="{
212
+ ...$attrs,
213
+ ...theme,
214
+ ...pluginProps.options as any,
215
+ modelValue: value,
216
+ name: name,
217
+ options: getOptions,
218
+ type: type,
219
+ label: getLabel || undefined,
220
+ }"
221
+ v-on="listeners"
222
+ >
223
+ <template
224
+ v-for="(_,slot) in $slots as Readonly<QOptionGroupSlots>"
225
+ :key="slot"
226
+ #[slot]="inputSlot"
227
+ >
228
+ <slot
229
+ :name="slot"
230
+ v-bind="inputSlot || {}"
231
+ />
232
+ </template>
233
+ <template
234
+ v-if="viewMode"
235
+ #control
236
+ >
237
+ <slot name="control">
238
+ <MInputFieldControl>
239
+ {{ viewModeValue ?? value }}
240
+ </MInputFieldControl>
241
+ </slot>
242
+ </template>
243
+ </q-option-group>
244
+ <slot
245
+ name="help"
246
+ v-bind="scopes"
247
+ >
248
+ <MHelpRow
249
+ v-if="!getLabel && help"
250
+ :text="help"
251
+ />
252
+ </slot>
253
+ <slot
254
+ name="bottom-input"
255
+ v-bind="scopes"
256
+ />
257
+ <slot
258
+ :options="options"
259
+ v-bind="scopes"
260
+ />
261
+ </MCol>
262
+ </template>
263
+
264
+ <style lang="sass">
265
+ $c: calc(100% / 3)
266
+
267
+ .m--options
268
+ .q-checkbox__inner,
269
+ .q-radio__inner,
270
+ .q-toggle__inner
271
+ align-self: flex-start
272
+
273
+ &__full_width
274
+ > div
275
+ .q-checkbox,
276
+ .q-radio,
277
+ .q-toggle,
278
+ .q-checkbox__label,
279
+ .q-radio__label,
280
+ .q-toggle__label
281
+ width: 100%
282
+
283
+ &__fit_width
284
+ margin-left: 0
285
+
286
+ > div
287
+ width: calc(100% / 3)
288
+ margin-left: 0
289
+ </style>
@@ -18,7 +18,17 @@ interface Props {
18
18
  position?: MModalMenuProps['position'];
19
19
  }
20
20
 
21
+ const modelValue = defineModel<boolean>({ required: !1, default: undefined })
21
22
  const { props: pluginOptions, __ } = useMyth()
23
+
24
+ type Emits = {
25
+ (e: 'beforeShow', evt?: Event): void;
26
+ (e: 'show', evt?: Event): void;
27
+ (e: 'beforeHide', evt?: Event): void;
28
+ (e: 'hide', evt?: Event): void;
29
+ }
30
+ const emit = defineEmits<Emits>()
31
+
22
32
  withDefaults(defineProps<Props>(), {
23
33
  noCloseBtn: () => !1,
24
34
  position: () => 'bottom'
@@ -31,6 +41,7 @@ defineOptions({
31
41
 
32
42
  <template>
33
43
  <q-popup-proxy
44
+ v-model="modelValue"
34
45
  :position="position"
35
46
  allow-focus-outside
36
47
  class="m--modal_menu"
@@ -39,6 +50,10 @@ defineOptions({
39
50
  no-shake
40
51
  persistent
41
52
  v-bind="{...pluginOptions.modalMenu,...$attrs}"
53
+ @hide="emit('hide', $event)"
54
+ @show="emit('show', $event)"
55
+ @before-show="emit('beforeShow',$event)"
56
+ @before-hide="emit('beforeHide',$event)"
42
57
  >
43
58
  <q-card v-bind="pluginOptions.modalMenuOptions?.card">
44
59
  <slot />
@@ -431,20 +431,30 @@ export const useDtHelpers = (options: MaybeRefOrGetter<MDatatableProps>) => {
431
431
  resetDialogForm({ values: init || {} }, { force: !0 })
432
432
  attrs && setValues(attrs, !1)
433
433
  }
434
- const openFilterDialog = () => {
434
+ const beforeShowFilterDialog = async () => {
435
435
  resetDialogForm({ values: {}, errors: {} }, { force: !0 })
436
- nextTick(() => {
436
+ await nextTick(() => {
437
437
  tempFilterForm.value = { ...filterForm.value }
438
+ })
439
+ }
440
+ const beforeCloseFilterDialog = async () => {
441
+ tempFilterForm.value = { ...filterForm.value }
442
+ }
443
+ const openFilterDialog = async () => {
444
+ await beforeShowFilterDialog()
445
+ await nextTick(() => {
438
446
  filterDialogModel.value = !0
439
447
  })
440
448
  }
441
- const saveFilterDialog = () => {
449
+ const saveFilterDialog = async () => {
442
450
  filterDialogModel.value = !1
443
- nextTick(() => (filterForm.value = { ...tempFilterForm.value }))
451
+ await nextTick(() => (filterForm.value = { ...tempFilterForm.value }))
444
452
  }
445
- const closeFilterDialog = () => {
453
+ const closeFilterDialog = async () => {
446
454
  filterDialogModel.value = !1
447
- tempFilterForm.value = { ...filterForm.value }
455
+ await nextTick(() => {
456
+ beforeCloseFilterDialog()
457
+ })
448
458
  }
449
459
  const onRemoveFilter = (key: string | number) => {
450
460
  const filter = filterForm.value
@@ -926,6 +936,7 @@ export const useDtHelpers = (options: MaybeRefOrGetter<MDatatableProps>) => {
926
936
  fetchDatatableItems,
927
937
  exportData,
928
938
  openDialogTimeout,
939
+ beforeCloseFilterDialog,
929
940
  openFilterDialog,
930
941
  saveFilterDialog,
931
942
  closeFilterDialog,
package/src/index.sass CHANGED
@@ -5,9 +5,13 @@
5
5
  // Github: https://github.com/mythpe
6
6
 
7
7
  //@import 'quasar/src/css/variables.sass'
8
- @import './style/ckeditor5.sass'
9
- @import './style/m-container.sass'
10
- @import './style/m-dt.sass'
11
- @import './style/main.sass'
12
- @import './style/print.sass'
8
+ @import './style/main'
9
+ @import './style/ckeditor5'
10
+ @import './style/m-container'
11
+ @import './style/m-dt'
12
+ @import './style/m-help-row'
13
+ @import './style/m-input'
14
+ @import './style/m-picker'
15
+ @import './style/m-select'
16
+ @import './style/print'
13
17
  @import './style/transition'
@@ -1,4 +1,4 @@
1
-
1
+ $control-max-width: 200px !default
2
2
  $fixed-dt-height: 80vh !default
3
3
 
4
4
  .touch
@@ -74,3 +74,12 @@ $fixed-dt-height: 80vh !default
74
74
 
75
75
  .grid-style-transition
76
76
  transition: transform .28s, background-color .28s
77
+
78
+ .screen--xs,
79
+ .screen--sm
80
+ .m--dt-btn-tooltip
81
+ display: none
82
+
83
+ .m--control-cell,
84
+ .m--control-header
85
+ width: $control-max-width
@@ -0,0 +1,4 @@
1
+ $m-help-row-margin-top: 4px !default
2
+
3
+ .m--help-row
4
+ margin-top: $m-help-row-margin-top
@@ -0,0 +1,47 @@
1
+ $m--input-helpers-margin: 5px !default
2
+ $radius-value: $generic-border-radius !default
3
+
4
+ [data-input-name].m--input__error
5
+ > .q-field
6
+ &:not(.q-field--disabled)
7
+ .q-field__label::after
8
+ color: var(--q-negative)
9
+
10
+ .m--input__top-label__content
11
+ color: var(--q-negative)
12
+
13
+
14
+ [data-input-name].m--input__required
15
+ &:not(.m--input__is-top-label)
16
+ > .q-field
17
+ &:not(.q-field--disabled)
18
+ .q-field__label::after
19
+ content: ' *'
20
+
21
+ .m--input__top-label__content::after
22
+ content: ' *'
23
+ color: var(--q-negative)
24
+
25
+
26
+ .m--input__color-preview
27
+ border: 1px solid var(--q-primary)
28
+ border-radius: $radius-value
29
+
30
+
31
+ .m--input__top-label,
32
+ .m--input__hint
33
+ margin-bottom: $m--input-helpers-margin
34
+
35
+ .m--input__caption
36
+ margin-bottom: $m--input-helpers-margin
37
+ font-size: 0.75rem
38
+ font-weight: 400
39
+ line-height: 1.25rem
40
+ letter-spacing: 0.03333em
41
+
42
+ .m--input
43
+ .m--sar-col
44
+ &__text
45
+ font-size: 18px
46
+ line-height: 16px
47
+ height: 15px
@@ -0,0 +1,7 @@
1
+ .m--date__picker,
2
+ .m--time__picker
3
+ .q-date__calendar-item
4
+ > div
5
+ text-overflow: ellipsis
6
+ white-space: nowrap
7
+ overflow: hidden
@@ -0,0 +1,4 @@
1
+ $m--select__popup-content: 300px !default
2
+
3
+ .m--select__popup-content
4
+ max-height: $m--select__popup-content
@@ -1,7 +1,6 @@
1
1
  @use 'sass:map'
2
2
 
3
3
  $m--row-margin-top: 1rem !default
4
- $m--input-helpers-margin: 5px !default
5
4
 
6
5
  // Flex.
7
6
  .flex-break
@@ -86,7 +85,6 @@ $bordered-style: $bordered-size solid var(--q-primary) !default
86
85
  .#{$bordered-class-name}
87
86
  border: $bordered-style
88
87
 
89
-
90
88
  @each $x in $alignsX
91
89
  .bordered-#{$x}
92
90
  border-#{$x}: $bordered-style
@@ -109,87 +107,15 @@ $bordered-style: $bordered-size solid var(--q-primary) !default
109
107
  .bordered-#{$y}
110
108
  border-#{$y}: $bordered-style
111
109
 
110
+
112
111
  .pre-text
113
112
  white-space-collapse: preserve-breaks
114
113
  white-space: pre-line
115
114
 
115
+
116
116
  pre
117
117
  max-width: 100%
118
118
 
119
- [data-input-name].m--input__error
120
- > .q-field
121
- &:not(.q-field--disabled)
122
- .q-field__label::after
123
- color: var(--q-negative)
124
-
125
- .m--input__top-label__content
126
- color: var(--q-negative)
127
-
128
-
129
- [data-input-name].m--input__required
130
- &:not(.m--input__is-top-label)
131
- > .q-field
132
- &:not(.q-field--disabled)
133
- .q-field__label::after
134
- content: ' *'
135
-
136
- .m--input__top-label__content::after
137
- content: ' *'
138
- color: var(--q-negative)
139
-
140
- .m--input__color-preview
141
- border: 1px solid var(--q-primary)
142
- border-radius: $radius-value
143
-
144
-
145
119
  .m--confirm.actions-between
146
120
  .q-card__actions
147
121
  justify-content: space-between !important
148
-
149
- .m--input__top-label,
150
- .m--input__hint
151
- margin-bottom: $m--input-helpers-margin
152
-
153
-
154
- .m--input__caption
155
- margin-bottom: $m--input-helpers-margin
156
- font-size: 0.75rem
157
- font-weight: 400
158
- line-height: 1.25rem
159
- letter-spacing: 0.03333em
160
-
161
- $control-max-width: 200px !default
162
-
163
- .m--control-cell,
164
- .m--control-header
165
- width: $control-max-width
166
-
167
- .screen--xs,
168
- .screen--sm
169
- .m--dt-btn-tooltip
170
- display: none
171
-
172
- $m-help-row-margin-top: 4px !default
173
-
174
- .m--help-row
175
- margin-top: $m-help-row-margin-top
176
-
177
- $m--select__popup-content: 300px !default
178
-
179
- .m--select__popup-content
180
- max-height: $m--select__popup-content
181
-
182
- .m--input
183
- .m--sar-col
184
- &__text
185
- font-size: 18px
186
- line-height: 16px
187
- height: 15px
188
-
189
- .m--date__picker,
190
- .m--time__picker
191
- .q-date__calendar-item
192
- > div
193
- text-overflow: ellipsis
194
- white-space: nowrap
195
- overflow: hidden