@mythpe/quasar-ui-qui 0.0.26-dev → 0.0.27-dev

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 (54) hide show
  1. package/index.d.ts +0 -4
  2. package/package.json +2 -1
  3. package/src/components/datatable/MDatatable.vue +2305 -0
  4. package/src/components/datatable/MDtAvatar.vue +49 -0
  5. package/src/components/datatable/MDtBtn.vue +153 -0
  6. package/src/components/datatable/MDtContextmenuItems.vue +54 -0
  7. package/src/components/datatable/index.ts +6 -0
  8. package/src/components/form/MAvatarViewer.vue +6 -3
  9. package/src/components/form/MAxios.vue +7 -4
  10. package/src/components/form/MCheckbox.vue +33 -9
  11. package/src/components/form/MDate.vue +4 -1
  12. package/src/components/form/MEmail.vue +4 -1
  13. package/src/components/form/MField.vue +4 -1
  14. package/src/components/form/MFile.vue +5 -2
  15. package/src/components/form/MForm.vue +4 -1
  16. package/src/components/form/MHiddenInput.vue +4 -1
  17. package/src/components/form/MInput.vue +1 -1
  18. package/src/components/form/MInputLabel.vue +4 -1
  19. package/src/components/form/MMobile.vue +4 -1
  20. package/src/components/form/MOptions.vue +255 -0
  21. package/src/components/form/MOtp.vue +292 -0
  22. package/src/components/form/MRadio.vue +5 -2
  23. package/src/components/form/MSelect.vue +4 -1
  24. package/src/components/form/MTime.vue +4 -1
  25. package/src/components/form/MToggle.vue +211 -0
  26. package/src/components/form/MUploader.vue +511 -0
  27. package/src/components/form/index.ts +9 -1
  28. package/src/components/grid/MColumn.vue +4 -1
  29. package/src/components/grid/MHelpRow.vue +5 -1
  30. package/src/components/index.ts +3 -0
  31. package/src/components/modal/MDialog.vue +58 -0
  32. package/src/components/modal/MModalMenu.vue +62 -0
  33. package/src/components/modal/MTooltip.vue +39 -0
  34. package/src/components/modal/index.ts +5 -0
  35. package/src/components/parials/UploaderItem.vue +298 -0
  36. package/src/components/parials/index.ts +3 -0
  37. package/src/components/transition/MTransition.vue +4 -1
  38. package/src/composable/useBindInput.ts +1 -1
  39. package/src/composable/useMyth.ts +20 -11
  40. package/src/index.sass +2 -1
  41. package/src/style/main.sass +104 -0
  42. package/src/style/print.sass +14 -0
  43. package/src/style/transition.sass +40 -0
  44. package/src/types/api-helpers.d.ts +11 -72
  45. package/src/types/components.d.ts +411 -105
  46. package/src/types/index.d.ts +5 -139
  47. package/src/types/install-options.d.ts +19 -0
  48. package/src/types/m-datatable.d.ts +316 -0
  49. package/src/types/m-geolocation.d.ts +16 -0
  50. package/src/types/m-helpers.d.ts +97 -0
  51. package/src/types/plugin-props-option.d.ts +301 -0
  52. package/src/utils/myth.ts +15 -1
  53. package/src/utils/vue-plugin.ts +34 -2
  54. package/src/types/dt.d.ts +0 -144
@@ -0,0 +1,255 @@
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 { reactive, toValue, useTemplateRef } from 'vue'
17
+ import { QField, QOptionGroup, type QOptionGroupSlots } from 'quasar'
18
+ import { useBindInput, useMyth } from '../../composable'
19
+ import { myth } from '../../utils'
20
+
21
+ type 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
+ viewMode?: Props['viewMode'];
38
+ viewModeValue?: Props['viewModeValue'];
39
+ topLabel?: Props['topLabel'];
40
+ color?: Props['color'];
41
+ type?: Props['type'];
42
+ keepColor?: Props['keepColor'];
43
+ service?: Props['service'];
44
+ fullWidth?: Props['fullWidth'];
45
+ fitWidth?: Props['fullWidth'];
46
+ fieldOptions?: Props['fieldOptions'];
47
+ }
48
+
49
+ const props = withDefaults(defineProps<P>(), {
50
+ name: () => '',
51
+ auto: undefined,
52
+ col: undefined,
53
+ xs: undefined,
54
+ sm: undefined,
55
+ md: undefined,
56
+ lg: undefined,
57
+ xl: undefined,
58
+ label: undefined,
59
+ caption: undefined,
60
+ hint: undefined,
61
+ placeholder: undefined,
62
+ help: undefined,
63
+ required: undefined,
64
+ rules: undefined,
65
+ viewMode: () => !1,
66
+ viewModeValue: undefined,
67
+ topLabel: undefined,
68
+ color: () => 'primary',
69
+ type: 'radio',
70
+ keepColor: undefined,
71
+ service: undefined,
72
+ fullWidth: () => !1,
73
+ fitWidth: () => !1,
74
+ fieldOptions: undefined
75
+ })
76
+ defineModel<Props['modelValue']>({ required: !1, default: undefined })
77
+ const loading = defineModel<Props['loading']>('loading', { required: !1, default: !1 })
78
+ const options = defineModel<MOptionsOptionContext[]>('options', { required: !1, default: undefined })
79
+ const helper = useBindInput<P>(() => props, 'options')
80
+ const { getLabel, inputRules, getProp } = helper
81
+ const inputScope = useField<Props['modelValue']>(() => props.name, inputRules, {
82
+ syncVModel: !0,
83
+ label: getLabel,
84
+ ...toValue<any>(props.fieldOptions)
85
+ })
86
+ const { value, errorMessage, handleChange, handleBlur } = inputScope
87
+
88
+ const listeners = {
89
+ blur: (v: any) => handleBlur(v, !0),
90
+ 'update:modelValue': (v: Props['modelValue']) => handleChange(v, !!errorMessage.value)
91
+ }
92
+ const input = useTemplateRef<InstanceType<typeof QField> | InstanceType<typeof QOptionGroup>>('input')
93
+ const scopes = reactive(inputScope)
94
+ defineExpose<typeof scopes & { input: typeof input }>({ input, ...scopes })
95
+ const { alertError, __ } = useMyth()
96
+ const { props: pluginProps } = myth
97
+ const fetchData = async () => {
98
+ if (props.service) {
99
+ loading.value = !0
100
+ try {
101
+ const { _data } = await props.service()
102
+ options.value = _data as any
103
+ } catch (e: any) {
104
+ alertError(e?._message || e?.message || 'Failed to fetch data')
105
+ } finally {
106
+ loading.value = !1
107
+ }
108
+ }
109
+ }
110
+ fetchData()
111
+ defineOptions({
112
+ name: 'MOptions',
113
+ inheritAttrs: !1
114
+ })
115
+ </script>
116
+
117
+ <template>
118
+ <MCol
119
+ :auto="auto"
120
+ :class="[$attrs.class,{'m--input__required':inputRules?.required!==undefined,'m--input__error':!!errorMessage,'m--input__view':viewMode}]"
121
+ :col="col"
122
+ :lg="lg"
123
+ :md="md"
124
+ :name="name"
125
+ :sm="sm"
126
+ :xs="xs"
127
+ >
128
+ <slot
129
+ name="top-input"
130
+ v-bind="scopes"
131
+ />
132
+ <slot name="top-label">
133
+ <MInputLabel
134
+ v-if="!!getLabel"
135
+ :field="scopes"
136
+ >
137
+ <MHelpRow
138
+ v-if="!!help"
139
+ :text="help"
140
+ tooltip
141
+ />
142
+ <MTransition>
143
+ <q-spinner-dots
144
+ v-if="loading"
145
+ color="primary"
146
+ size="25px"
147
+ />
148
+ </MTransition>
149
+ </MInputLabel>
150
+ </slot>
151
+ <slot name="caption">
152
+ <div
153
+ v-if="!!caption"
154
+ class="m--input__caption"
155
+ >
156
+ {{ __(caption) }}
157
+ </div>
158
+ </slot>
159
+ <MTransition>
160
+ <div
161
+ v-if="!!errorMessage"
162
+ class="text-negative text-caption"
163
+ >
164
+ <q-icon
165
+ v-if="!!errorMessage"
166
+ color="negative"
167
+ name="ion-ios-information-circle-outline"
168
+ size="20px"
169
+ />
170
+ {{ errorMessage }}
171
+ </div>
172
+ </MTransition>
173
+ <component
174
+ :is="viewMode ? QField : QOptionGroup"
175
+ ref="input"
176
+ :class="{'m--options': !0, 'm--options__full_width': fullWidth, 'm--options__fit_width': fitWidth }"
177
+ :color="!!errorMessage ? 'negative' : getProp('color')"
178
+ :error="viewMode ? !!errorMessage : undefined"
179
+ :error-message="viewMode ? errorMessage : undefined"
180
+ :hint="viewMode ? __(hint) : undefined"
181
+ :keep-color="!!errorMessage ? !0 : getProp('keepColor')"
182
+ :label="getLabel"
183
+ :model-value="value"
184
+ :options="options"
185
+ :type="viewMode ? undefined : type"
186
+ v-bind="{ ...pluginProps.options as any,...( viewMode ? pluginProps.field : {} ), ...$attrs, ...( viewMode ? { stackLabel: !0 } : {} ) }"
187
+ v-on="listeners"
188
+ >
189
+ <template
190
+ v-for="(_,slot) in $slots as Readonly<QOptionGroupSlots>"
191
+ :key="slot"
192
+ #[slot]="inputSlot"
193
+ >
194
+ <slot
195
+ :name="slot"
196
+ v-bind="inputSlot || {}"
197
+ />
198
+ </template>
199
+ <template
200
+ v-if="viewMode"
201
+ #control
202
+ >
203
+ <slot name="control">
204
+ <MInputFieldControl>
205
+ {{ viewModeValue ?? value }}
206
+ </MInputFieldControl>
207
+ </slot>
208
+ </template>
209
+ </component>
210
+ <slot
211
+ name="help"
212
+ v-bind="scopes"
213
+ >
214
+ <MHelpRow
215
+ v-if="!getLabel"
216
+ :text="help"
217
+ />
218
+ </slot>
219
+ <slot
220
+ name="bottom-input"
221
+ v-bind="scopes"
222
+ />
223
+ <slot
224
+ :options="options"
225
+ v-bind="scopes"
226
+ />
227
+ </MCol>
228
+ </template>
229
+
230
+ <style lang="sass">
231
+ $c: calc(100% / 3)
232
+
233
+ .m--options
234
+ .q-checkbox__inner,
235
+ .q-radio__inner,
236
+ .q-toggle__inner
237
+ align-self: flex-start
238
+
239
+ &__full_width
240
+ > div
241
+ .q-checkbox,
242
+ .q-radio,
243
+ .q-toggle,
244
+ .q-checkbox__label,
245
+ .q-radio__label,
246
+ .q-toggle__label
247
+ width: 100%
248
+
249
+ &__fit_width
250
+ margin-left: 0
251
+
252
+ > div
253
+ width: calc(100% / 3)
254
+ margin-left: 0
255
+ </style>
@@ -0,0 +1,292 @@
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 { isNaN } from 'lodash'
15
+ import { computed, nextTick, onBeforeUnmount, onBeforeUpdate, ref, watch, watchEffect } from 'vue'
16
+ import { date } from 'quasar'
17
+ import type { MOtpProps as Props } from '../../types'
18
+ import { useMyth } from '../../composable'
19
+ import { myth } from '../../utils'
20
+
21
+ export interface P {
22
+ // modelValue?: Props['modelValue'];
23
+ inputLength?: Props['inputLength'];
24
+ numeric?: Props['numeric'];
25
+ time?: Props['time'];
26
+ hideTime?: Props['hideTime'];
27
+ hideSendAgain?: Props['hideSendAgain'];
28
+ topLabel?: Props['topLabel'];
29
+ topLabelProps?: Props['topLabelProps'];
30
+ autofocus?: Props['autofocus'];
31
+ errors?: Props['errors'];
32
+ }
33
+
34
+ type Emits = {
35
+ (e: 'end'): void;
36
+ (e: 'send'): void;
37
+ }
38
+ const emit = defineEmits<Emits>()
39
+ const { __ } = useMyth()
40
+ const { props: pluginOptions } = myth
41
+ const props = withDefaults(defineProps<P>(), {
42
+ // modelValue: undefined,
43
+ inputLength: () => 6,
44
+ numeric: () => !0,
45
+ time: () => 120,
46
+ hideTime: () => !1,
47
+ hideSendAgain: () => !1,
48
+ topLabel: undefined,
49
+ topLabelProps: undefined,
50
+ autofocus: () => !1,
51
+ errors: () => ([])
52
+ })
53
+ const modelValue = defineModel<Props['modelValue']>({ required: !1, default: undefined })
54
+ const otpErrors = computed(() => props.errors ? props.errors : [])
55
+ const length = computed<number>(() => parseInt(props.inputLength?.toString() || '0'))
56
+ const fields = ref<any>([])
57
+ const fieldValues = ref<(string | number | null | undefined)[]>([])
58
+ watchEffect(() => {
59
+ fieldValues.value = (modelValue.value || '').toString().split('').slice(0, length.value)
60
+ })
61
+
62
+ const composite = computed(() => {
63
+ const nonNullFields = fieldValues.value.filter(v => (v || v?.toString() !== '0'))
64
+ if (length.value !== nonNullFields.length) {
65
+ return ''
66
+ }
67
+ return nonNullFields.join('')
68
+ })
69
+
70
+ watch(composite, () => {
71
+ if (composite.value) {
72
+ if (props.numeric !== !1) {
73
+ if (!isNaN(composite.value) && composite.value?.toString()?.length?.toString() === props.inputLength.toString()) {
74
+ modelValue.value = composite.value
75
+ }
76
+ } else {
77
+ modelValue.value = composite.value
78
+ }
79
+ }
80
+ })
81
+
82
+ // make sure to reset the refs before each update
83
+ onBeforeUpdate(() => {
84
+ fields.value = []
85
+ })
86
+
87
+ const updateFieldRef = (element: any, index: number) => {
88
+ if (element) {
89
+ fields.value[index] = element
90
+ }
91
+ }
92
+
93
+ const focus = (index: number) => {
94
+ if (index >= 0) {
95
+ if (index < length.value) {
96
+ fields.value[index]?.select()
97
+ } else {
98
+ if (composite.value) {
99
+ fields.value[index - 1]?.blur()
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ const blur = (index: number) => {
106
+ fields.value[index]?.blur()
107
+ }
108
+
109
+ const onUpdate = (value: string | number | null, index: number) => {
110
+ if (value) {
111
+ if (props.numeric !== !1 && isNaN(value)) {
112
+ nextTick(() => {
113
+ setTimeout(() => {
114
+ focus(index)
115
+ }, 100)
116
+ })
117
+ return
118
+ }
119
+ focus(index + 1)
120
+ if (index === (length.value - 1)) {
121
+ blur(index)
122
+ }
123
+ }
124
+ }
125
+
126
+ const onKeyDown = (evt: KeyboardEvent, index: number) => {
127
+ if (props.numeric !== !1 && evt.key && evt.key.toString() !== '0' && !parseInt(evt.key) && evt.key?.length === 1) {
128
+ evt.preventDefault()
129
+ }
130
+ }
131
+ const onKeyUp = (evt: KeyboardEvent, index: number) => {
132
+ const key = evt.key
133
+ if (['Tab', 'Shift', 'Meta', 'Control', 'Alt', 'Enter', ' '].includes(key)) {
134
+ return
135
+ }
136
+
137
+ if (['Delete'].includes(key)) {
138
+ focus(index - 1)
139
+ return
140
+ }
141
+
142
+ if (key === 'ArrowLeft' || key === 'Backspace') {
143
+ focus(index - 1)
144
+ } else if (key === 'ArrowRight') {
145
+ focus(index + 1)
146
+ }
147
+
148
+ // The input is fill & replace the value
149
+ // if (key.length === 1) {
150
+ // onUpdate(key, index)
151
+ // const t = [...fieldValues.value]
152
+ // t[index] = key
153
+ // fieldValues.value = t
154
+ // }
155
+ }
156
+ const onPaste = (evt: ClipboardEvent, index: number) => {
157
+ const value: any = evt.clipboardData?.getData('text')?.toString() || ''
158
+ if (props.numeric !== !1 && isNaN(value)) {
159
+ evt.preventDefault()
160
+ return
161
+ }
162
+ if (value?.length > 0) {
163
+ fieldValues.value = value.slice(0, length.value).split('').map((e: string) => parseInt(e) || 0)
164
+ blur(index)
165
+ }
166
+ }
167
+
168
+ const seconds = ref<number>(0)
169
+ const temp = ref<number>(0)
170
+ watch(() => seconds.value, v => (temp.value = v))
171
+ const startTiming = () => {
172
+ if (props.hideTime) {
173
+ return
174
+ }
175
+
176
+ if (seconds.value > 0) {
177
+ --seconds.value
178
+ if (!seconds.value) {
179
+ emit('end')
180
+ }
181
+ }
182
+ }
183
+ const getTime = computed<string | null>(() => {
184
+ const nullValue = null
185
+ if (props.hideTime) {
186
+ return nullValue
187
+ }
188
+ if (seconds.value < 1) {
189
+ return '00:00'
190
+ }
191
+
192
+ const newDate = date.buildDate({ minutes: 0, seconds: seconds.value, milliseconds: 0 })
193
+ const m = newDate.getMinutes()
194
+ const s = newDate.getSeconds()
195
+ return `${(m < 9 ? '0' : '') + m}:${(s < 9 ? '0' : '') + s}`
196
+ })
197
+ const disabled = computed(() => seconds.value > 0)
198
+ let interval: any = null
199
+ const clear = () => {
200
+ interval && clearInterval(interval)
201
+ }
202
+ const start = () => {
203
+ if (props.hideTime) {
204
+ return
205
+ }
206
+ clear()
207
+ seconds.value = parseInt(props.time?.toString()) || 120
208
+ interval = setInterval(() => startTiming(), 1000)
209
+ }
210
+ watch(() => props.time, () => start(), { immediate: !0, deep: !0 })
211
+ onBeforeUnmount(() => clear())
212
+ const onSend = () => {
213
+ if (disabled.value) {
214
+ return
215
+ }
216
+ emit('send')
217
+ }
218
+ defineExpose({ start })
219
+ defineOptions({
220
+ name: 'MOtp',
221
+ inheritAttrs: !1
222
+ })
223
+ </script>
224
+
225
+ <template>
226
+ <MCol
227
+ auto
228
+ class="text-center"
229
+ v-bind="$attrs"
230
+ >
231
+ <slot name="before-all" />
232
+ <MRow
233
+ v-if="!!topLabel"
234
+ class="justify-start q-mb-md text-body1"
235
+ v-bind="topLabelProps"
236
+ >
237
+ <div>
238
+ {{ __(topLabel) }}
239
+ </div>
240
+ </MRow>
241
+ <div :class="`row ${$q.lang.rtl ? 'reverse' : ''} q-gutter-x-sm justify-center`">
242
+ <q-input
243
+ v-for="i in length"
244
+ :key="i"
245
+ :ref="el => updateFieldRef(el, i - 1)"
246
+ v-model="fieldValues[i - 1]"
247
+ :autofocus="autofocus && i === 1"
248
+ :error="otpErrors.length > 0"
249
+ hide-bottom-space
250
+ input-class="text-center"
251
+ maxlength="1"
252
+ no-error-icon
253
+ outlined
254
+ style="width: 6ch"
255
+ v-bind="{...pluginOptions.otp as any,...$attrs}"
256
+ @keydown="onKeyDown($event, i - 1)"
257
+ @keyup="onKeyUp($event, i - 1)"
258
+ @paste.prevent="onPaste($event,i - 1)"
259
+ @update:model-value="onUpdate($event, i - 1)"
260
+ />
261
+ </div>
262
+ <div
263
+ v-if="otpErrors.length > 0"
264
+ class="q-my-md text-negative"
265
+ >
266
+ {{ otpErrors[0] }}
267
+ </div>
268
+ <slot name="after-input" />
269
+ <MFadeTransition>
270
+ <div
271
+ v-if="!hideTime"
272
+ class="q-mt-sm"
273
+ >
274
+ <span>{{ __('myth.otp.expire_line') }}:&nbsp;</span>
275
+ <span>{{ getTime }}</span>
276
+ </div>
277
+ </MFadeTransition>
278
+ <MFadeTransition>
279
+ <div
280
+ v-if="!hideSendAgain"
281
+ class="q-mt-sm"
282
+ >
283
+ <span>{{ __('myth.otp.send_again_title') }}&nbsp;</span>
284
+ <span
285
+ :class="{'text-decoration-underline':!0, disabled,'cursor-pointer': !disabled}"
286
+ @click="onSend()"
287
+ >{{ __('myth.otp.send_again_btn') }}</span>
288
+ </div>
289
+ </MFadeTransition>
290
+ <slot name="after-all" />
291
+ </MCol>
292
+ </template>
@@ -6,9 +6,12 @@
6
6
  - Github: https://github.com/mythpe
7
7
  -->
8
8
 
9
- <script lang="ts" setup>
9
+ <script
10
+ lang="ts"
11
+ setup
12
+ >
10
13
  import { useField } from 'vee-validate'
11
- import { defineProps, reactive, toValue, useTemplateRef } from 'vue'
14
+ import { reactive, toValue, useTemplateRef } from 'vue'
12
15
  import { useBindInput, useMyth } from '../../composable'
13
16
  import type { MRadioProps as Props } from '../../types'
14
17
  import { QField, QRadio } from 'quasar'
@@ -6,7 +6,10 @@
6
6
  - Github: https://github.com/mythpe
7
7
  -->
8
8
 
9
- <script lang="ts" setup>
9
+ <script
10
+ lang="ts"
11
+ setup
12
+ >
10
13
 
11
14
  import { useField } from 'vee-validate'
12
15
  import type { MSelectProps as Props } from '../../types'
@@ -6,7 +6,10 @@
6
6
  - Github: https://github.com/mythpe
7
7
  -->
8
8
 
9
- <script lang="ts" setup>
9
+ <script
10
+ lang="ts"
11
+ setup
12
+ >
10
13
  import type { MInputSlots, MTimeProps as Props } from '../../types'
11
14
  import { useTemplateRef } from 'vue'
12
15
  import MPicker from './MPicker.vue'