@mythpe/quasar-ui-qui 0.0.23 → 0.0.24-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 (69) hide show
  1. package/index.d.ts +17 -0
  2. package/package.json +14 -9
  3. package/src/boot/register.ts +14 -0
  4. package/src/components/form/MAvatarViewer.vue +324 -0
  5. package/src/components/form/MBtn.vue +271 -93
  6. package/src/components/form/MCheckbox.vue +123 -0
  7. package/src/components/form/MColor.vue +122 -0
  8. package/src/components/form/MDate.vue +47 -0
  9. package/src/components/form/MEditor.vue +285 -0
  10. package/src/components/form/MEmail.vue +40 -0
  11. package/src/components/form/MField.vue +142 -0
  12. package/src/components/form/MFile.vue +209 -0
  13. package/src/components/form/MForm.vue +83 -0
  14. package/src/components/form/MHidden.vue +83 -0
  15. package/src/components/form/MHiddenInput.vue +55 -0
  16. package/src/components/form/MInput.vue +178 -0
  17. package/src/components/form/MInputFieldControl.vue +27 -0
  18. package/src/components/form/MInputLabel.vue +35 -0
  19. package/src/components/form/MMobile.vue +37 -0
  20. package/src/components/form/MPicker.vue +310 -0
  21. package/src/components/form/MRadio.vue +175 -0
  22. package/src/components/form/MSelect.vue +343 -0
  23. package/src/components/form/MTime.vue +45 -0
  24. package/src/components/form/index.ts +51 -0
  25. package/src/components/grid/MBlock.vue +40 -18
  26. package/src/components/grid/MCol.vue +11 -15
  27. package/src/components/grid/MColumn.vue +8 -0
  28. package/src/components/grid/MContainer.vue +22 -13
  29. package/src/components/grid/MHelpRow.vue +9 -12
  30. package/src/components/grid/MRow.vue +31 -10
  31. package/src/components/grid/index.ts +16 -0
  32. package/src/components/index.ts +12 -0
  33. package/src/components/transition/MFadeTransition.vue +27 -0
  34. package/src/components/transition/MFadeXTransition.vue +26 -0
  35. package/src/components/transition/MTransition.vue +41 -0
  36. package/src/components/transition/index.ts +13 -0
  37. package/src/components/typography/MTypingString.vue +8 -0
  38. package/src/components/typography/index.ts +11 -0
  39. package/src/composable/index.ts +12 -0
  40. package/src/composable/useBindInput.ts +209 -0
  41. package/src/composable/useError.ts +11 -0
  42. package/src/composable/useMyth.ts +294 -0
  43. package/src/composable/useValue.ts +12 -0
  44. package/src/index.common.js +19 -1
  45. package/src/index.esm.js +18 -3
  46. package/src/index.js +19 -0
  47. package/src/index.sass +8 -26
  48. package/src/index.ts +18 -4
  49. package/src/index.umd.js +16 -2
  50. package/src/style/m-container.sass +13 -0
  51. package/src/style/main.sass +42 -0
  52. package/src/types/api-helpers.d.ts +120 -0
  53. package/src/types/components.d.ts +682 -28
  54. package/src/types/dt.d.ts +142 -0
  55. package/src/types/index.d.ts +153 -1
  56. package/src/types/lodash.d.ts +26 -0
  57. package/src/types/quasar-helpers.d.ts +7 -0
  58. package/src/types/theme.d.ts +12 -0
  59. package/src/utils/Helpers.ts +321 -0
  60. package/src/utils/Str.ts +210 -0
  61. package/src/utils/index.ts +13 -0
  62. package/src/utils/myth.ts +90 -0
  63. package/src/utils/vee-rules.ts +32 -0
  64. package/src/utils/vue-plugin.ts +122 -0
  65. package/tsconfig.json +9 -13
  66. package/src/myth.ts +0 -30
  67. package/src/types/myth.ts +0 -42
  68. package/src/vue-plugin.ts +0 -41
  69. package/types.d.ts +0 -1
@@ -0,0 +1,142 @@
1
+ import type { QTableProps } from 'quasar'
2
+ import type { GenericFormValues, MDatatableProps, MDtBtnProps } from './components'
3
+ import type { MaybeRef, Ref, UnwrapRef } from 'vue'
4
+ import type { AxiosResponse } from 'axios'
5
+ type Generic = Record<any, any>;
6
+
7
+ export type MDtItem<T extends object = Record<keyof T, any>> = T & {
8
+ id: string | number;
9
+ [K: keyof T]: any;
10
+ }
11
+ export type MDtItemIndex = number;
12
+ export type MDtExportOptions = 'pdf' | 'excel';
13
+
14
+ type MDDIP<T extends Generic = Generic | any> = Partial<MDtItem> & Record<string, any> | T;
15
+ export type MDatatableDialogsOptions<T extends MDDIP = MDDIP> = {
16
+ filter: Ref<boolean>;
17
+ show: Ref<boolean>;
18
+ form: Ref<boolean>;
19
+ isUpdate: Ref<boolean>;
20
+ item: T | MaybeRef<MDDIP<T>> | UnwrapRef<MDDIP<T>> | Record<string, any> | undefined;
21
+ index: Ref<MDtItemIndex | undefined>;
22
+ errors: Record<string | number | symbol, string[]> | any;
23
+ }
24
+
25
+ type E = MDatatableDialogsOptions['item'];
26
+ export type GenericMDtBtn<T extends E = E> = Record<string, any> & {
27
+ name: string;
28
+ label?: string;
29
+ contextLabel?: string | null;
30
+ tooltip?: string;
31
+ click?: (item: UnwrapRef<T> | Ref<T> | T, index: UnwrapRef<MDatatableDialogsOptions['index']>) => void;
32
+ multiClick?: (items: T[]) => void;
33
+ showIf?: boolean | ((item: UnwrapRef<MDatatableDialogsOptions['item']>, index: UnwrapRef<MDatatableDialogsOptions['index']>) => boolean);
34
+ order?: number;
35
+ attr?: Partial<MDtBtnProps> & Partial<{ icon?: string; textColor?: string; color?: string; }>;
36
+ }
37
+
38
+ export interface ApiServiceParams {
39
+ filter?: Record<string, any>;
40
+ search?: string | null;
41
+ searchColumns?: string[] | string;
42
+ // headers: string[];
43
+ headerItems?: any[] | string[] | string;
44
+ ids?: number[];
45
+ indexType: 'index' | 'pdf' | 'excel';
46
+ // For Datatable, index,export-pdf|excel,update,create,show,delete
47
+ fdt: 'i' | 'e' | 'u' | 'c' | 's' | 'd';
48
+ requestWith?: string;
49
+ itemsPerPage: number;
50
+ page: number;
51
+ sortBy?: string;
52
+ sortDesc?: number;
53
+ toUrl?: MDtExportOptions | boolean;
54
+
55
+ [key: string]: any;
56
+ }
57
+ export type MDtServiceNameCallbackProp = (() => Record<string, (() => Promise<AxiosResponse>)>)
58
+ export type MDtServiceNameStringProp = string
59
+ export type MDtRequestParamsCallbackProp = (params: ApiServiceParams) => Partial<GenericFormValues>
60
+ export type MDtRequestParamsObjectProp = Partial<GenericFormValues>
61
+
62
+ export type ParseHeaderOptions = {
63
+ controlKey?: 'control' | string
64
+ controlStyle?: 'max-width: 150px' | string
65
+ align?: 'left' | 'right' | 'center' | undefined
66
+ sortable?: boolean | undefined;
67
+ classes?: string | (() => string),
68
+ noSort?: string[]
69
+ }
70
+
71
+ // export interface ParsedHeader {
72
+ // /**
73
+ // * Unique id, identifies column, (used by pagination.sortBy, 'body-cell-[name]' slot, ...)
74
+ // */
75
+ // name: string;
76
+ // /**
77
+ // * Label for header
78
+ // */
79
+ // label: string;
80
+ // /**
81
+ // * Row Object property to determine value for this column or function which maps to the required property
82
+ // * @param row The current row being processed
83
+ // * @returns Value for this column
84
+ // */
85
+ // field: string | ((row: any) => any);
86
+ // /**
87
+ // * If we use visible-columns, this col will always be visible
88
+ // */
89
+ // required?: boolean;
90
+ // /**
91
+ // * Horizontal alignment of cells in this column
92
+ // * Default value: right
93
+ // */
94
+ // align?: 'left' | 'right' | 'center';
95
+ // /**
96
+ // * Tell QTable you want this column sortable
97
+ // */
98
+ // sortable?: boolean;
99
+ // /**
100
+ // * Compare function if you have some custom data or want a specific way to compare two rows
101
+ // * @param a Value of the first comparison term
102
+ // * @param b Value of the second comparison term
103
+ // * @param rowA Full Row object in which is contained the first term
104
+ // * @param rowB Full Row object in which is contained the second term
105
+ // * @returns Comparison result of term 'a' with term 'b'. Less than 0 when 'a' should come first; greater than 0 if 'b' should come first; equal to 0 if their position must not be changed with respect to each other
106
+ // */
107
+ // sort?: (a: any, b: any, rowA: any, rowB: any) => number;
108
+ // /**
109
+ // * Set column sort order: 'ad' (ascending-descending) or 'da' (descending-ascending); Overrides the 'column-sort-order' prop
110
+ // * Default value: ad
111
+ // */
112
+ // sortOrder?: 'ad' | 'da';
113
+ // /**
114
+ // * Function you can apply to format your data
115
+ // * @param val Value of the cell
116
+ // * @param row Full Row object in which the cell is contained
117
+ // * @returns The resulting formatted value
118
+ // */
119
+ // format?: (val: any, row: any) => any;
120
+ // /**
121
+ // * Style to apply on normal cells of the column
122
+ // * @param row The current row being processed
123
+ // */
124
+ // style?: string | ((row: any) => string);
125
+ // /**
126
+ // * Classes to add on normal cells of the column
127
+ // * @param row The current row being processed
128
+ // */
129
+ // classes?: string | ((row: any) => string);
130
+ // /**
131
+ // * Style to apply on header cells of the column
132
+ // */
133
+ // headerStyle?: string;
134
+ // /**
135
+ // * Classes to add on header cells of the column
136
+ // */
137
+ // headerClasses?: string;
138
+ // }
139
+
140
+ export type MDtColumn = QTableProps['columns'][number]
141
+
142
+ export type MDtHeadersParameter = MDtColumn[] | (keyof MDatatableProps['defaultItem'])[]
@@ -1,2 +1,154 @@
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
+ import type { QBtnProps, QFieldProps, QNotifyCreateOptions } from 'quasar'
10
+ import {
11
+ MAvatarViewerProps,
12
+ MBlockProps,
13
+ MBtnProps,
14
+ MCheckboxProps,
15
+ MColProps,
16
+ MColumnProps,
17
+ MContainerProps,
18
+ MDateProps,
19
+ MEditorProps,
20
+ MFileProps,
21
+ MHelpRowProps,
22
+ MInputProps,
23
+ MPickerProps,
24
+ MRadioProps,
25
+ MRowProps,
26
+ MSelectProps,
27
+ MTimeProps,
28
+ MTypingStringProps
29
+ } from './components'
30
+ import { myth } from '../utils'
31
+ import { ThemeBtn, ThemeFluid, ThemeInput, ThemeRounded, ThemeShadow, ThemeSize } from './theme'
32
+
33
+ /**
34
+ * Default loading q-btn loading slot.
35
+ */
36
+ export type BtnLoading = {
37
+ type: 'audio' | 'ball' | 'bars' | 'box' | 'clock' | 'comment' | 'cube' | 'dots' | 'facebook' | 'gears' | 'grid' | 'hearts' | 'hourglass' | 'infinity' | 'ios' | 'orbit' | 'oval' | 'pie' | 'puff' | 'radio' | 'rings' | 'tail' | 'spinner';
38
+ color?: string | undefined;
39
+ size?: string | undefined;
40
+ noLabel?: boolean;
41
+ }
42
+
43
+ export interface PropsContext {
44
+ // Grid.
45
+ /**
46
+ * MBlock component.
47
+ */
48
+ block?: Partial<MBlockProps>;
49
+ /**
50
+ * MCol component.
51
+ */
52
+ col?: Partial<MColProps>;
53
+ /**
54
+ * MColumn component.
55
+ */
56
+ column?: Partial<MColumnProps>;
57
+ /**
58
+ * MContainer component.
59
+ */
60
+ container?: Partial<MContainerProps>;
61
+ /**
62
+ * MHelpRow component.
63
+ */
64
+ helpRow?: Partial<MHelpRowProps>;
65
+ /**
66
+ * MRow component.
67
+ */
68
+ row?: Partial<MRowProps>;
69
+ /**
70
+ * MTypingString component.
71
+ */
72
+ typingString?: Partial<MTypingStringProps>;
73
+ /**
74
+ * MAvatarViewer component.
75
+ */
76
+ avatarViewer?: Partial<MAvatarViewerProps>;
77
+ /**
78
+ * MBtn component.
79
+ */
80
+ btn?: Partial<MBtnProps>;
81
+ /**
82
+ * MInput component.
83
+ */
84
+ input?: Partial<MInputProps>;
85
+ /**
86
+ * MFile component.
87
+ */
88
+ file?: Partial<MFileProps>;
89
+ /**
90
+ * MMobile component.
91
+ */
92
+ mobile?: Partial<MInputProps>;
93
+ /**
94
+ * MInput view mode props.
95
+ */
96
+ field?: Partial<QFieldProps>;
97
+ /**
98
+ * MCheckbox component.
99
+ */
100
+ checkbox?: Partial<MCheckboxProps>;
101
+ /**
102
+ * MRadio component.
103
+ */
104
+ radio?: Partial<MRadioProps>;
105
+ /**
106
+ * MSelect component.
107
+ */
108
+ select?: Partial<MSelectProps>;
109
+ /**
110
+ * MPicker component.
111
+ */
112
+ picker?: Partial<MPickerProps>;
113
+ /**
114
+ * q-btn component props.
115
+ */
116
+ pickerBtn?: Partial<QBtnProps>;
117
+ /**
118
+ * MDate component.
119
+ */
120
+ date?: Partial<MDateProps>;
121
+ /**
122
+ * MEditor component.
123
+ */
124
+ editor?: Partial<MEditorProps>;
125
+ /**
126
+ * MTime component.
127
+ */
128
+ time?: Partial<MTimeProps>;
129
+ /**
130
+ * Notify Props.
131
+ */
132
+ notify?: Partial<QNotifyCreateOptions>;
133
+ }
134
+
135
+ export interface InstallOptions {
136
+ size?: ThemeSize;
137
+ rounded?: ThemeRounded;
138
+ shadow?: ThemeShadow;
139
+ fluid?: ThemeFluid;
140
+ rules?: string[];
141
+ btnLoading?: BtnLoading;
142
+ props?: PropsContext;
143
+ themeInput?: ThemeInput;
144
+ themeBtn?: ThemeBtn;
145
+ }
146
+
147
+ export type MythContext = typeof myth;
148
+
149
+ export * from './api-helpers'
1
150
  export * from './components'
2
- export * from './myth'
151
+ export * from './dt'
152
+ export * from './lodash'
153
+ export * from './quasar-helpers'
154
+ export * from './theme'
@@ -0,0 +1,26 @@
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
+ /* eslint-disable */
9
+
10
+ declare module 'lodash' {
11
+ interface LoDashStatic {
12
+ /**
13
+ * Converts string to pascal case.
14
+ *
15
+ * @param string The string to convert.
16
+ * @return Returns the pascal cased string.
17
+ */
18
+ pascalCase (string?: string): string;
19
+
20
+ pluralize (string?: string): string;
21
+
22
+ singularize (string?: string): string;
23
+ }
24
+ }
25
+
26
+ export {}
@@ -0,0 +1,7 @@
1
+ import type { DialogChainObject, QNotifyCreateOptions, QNotifyUpdateOptions } from 'quasar'
2
+
3
+ export type Vue3MAlertMessageOptions = QNotifyCreateOptions | string;
4
+
5
+ export type Vue3MAlertMessage = (props?: QNotifyUpdateOptions) => void;
6
+
7
+ export type Vue3MConfirmMessage = DialogChainObject
@@ -0,0 +1,12 @@
1
+ import type { QBtnProps, QInputProps } from 'quasar'
2
+
3
+ export type ThemeSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none' | string;
4
+ export type ThemeShadow = string | number | 'transition' | 'none';
5
+ export type ThemeRounded = boolean;
6
+ export type ThemeFluid = boolean;
7
+ export type ThemeInput =
8
+ Partial<Pick<QInputProps, 'standout' | 'dense' | 'filled' | 'outlined' | 'rounded' | 'borderless' | 'counter' | 'noErrorIcon' | 'hideBottomSpace' | 'bottomSlots' | 'clearIcon' | 'itemAligned' | 'square' | 'stackLabel'>>
9
+ & {
10
+ topLabel?: boolean;
11
+ }
12
+ export type ThemeBtn = Partial<Pick<QBtnProps, 'flat' | 'outline' | 'push' | 'unelevated' | 'noCaps' | 'rounded' | 'glossy' | 'square' | 'padding' | 'ripple' | 'dense'>>
@@ -0,0 +1,321 @@
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
+ import { AxiosInstance, AxiosRequestConfig } from 'axios'
10
+ import lodash from 'lodash'
11
+ import { openURL, scroll } from 'quasar'
12
+ import type {
13
+ ConfigType,
14
+ DownloadFromResponse,
15
+ DownloadFromResponseCode,
16
+ HelpersStubSchema,
17
+ ParamsType,
18
+ UrlType
19
+ } from '../types'
20
+
21
+ import { nextTick } from 'vue'
22
+
23
+ export const Helpers = {
24
+ appendArray (formData: FormData, values: File | Blob | Record<string, any> | any, name?: string | null | undefined) {
25
+ let value: never | any
26
+ if ((values instanceof File || values instanceof Blob) && name) {
27
+ const _name = values instanceof File ? values.name : name
28
+ formData.append(name, values, _name)
29
+ } else {
30
+ for (const key in values) {
31
+ value = values[key]
32
+ if (value !== null && value !== undefined && typeof value === 'object') {
33
+ const k = name ? name + '[' + key + ']' : key
34
+ if (lodash.isArray(value) && value.length < 1) {
35
+ formData.append(`${key}`, '')
36
+ } else {
37
+ this.appendArray(formData, value, k)
38
+ }
39
+ } else {
40
+ if (value === !0) {
41
+ value = 1
42
+ }
43
+ if (value === false) {
44
+ value = 0
45
+ }
46
+ if (value === null || value === undefined) {
47
+ value = ''
48
+ // console.log('null----', name,key, value)
49
+ }
50
+ // if (value !== undefined) {
51
+ if (name) {
52
+ formData.append(name + '[' + key + ']', value)
53
+ } else {
54
+ formData.append(key, value)
55
+ }
56
+ // }
57
+ }
58
+ }
59
+ }
60
+ return formData
61
+ },
62
+ Stub (baseUrl: UrlType, axios: () => AxiosInstance): HelpersStubSchema {
63
+ const makeUrl = Helpers.StubUrl(baseUrl)
64
+ return {
65
+ async index (config?: ConfigType) {
66
+ const u = makeUrl()
67
+ return axios().get(u, config)
68
+ // return typeof config === 'boolean' ? u : axios().get(u, config)
69
+ },
70
+ async staticIndex (config?: ConfigType) {
71
+ const u = `Static${baseUrl ? `/${baseUrl}` : ''}`
72
+ return axios().get(u, config)
73
+ // config = config || {}
74
+ // config.params = {
75
+ // page: 1,
76
+ // itemsPerPage: -1,
77
+ // ...(config.params ?? {})
78
+ // }
79
+ // return axios().get(u, config)
80
+ },
81
+ async export (data?: ParamsType, config?: AxiosRequestConfig) {
82
+ return axios().post(makeUrl('Export'), data, config)
83
+ },
84
+ async store (data?: ParamsType, config?: AxiosRequestConfig) {
85
+ const u = makeUrl()
86
+ // if (typeof data === 'boolean') {
87
+ // return u
88
+ // }
89
+ const formData = new FormData()
90
+ data && Helpers.appendArray(formData, data)
91
+ return axios().post(u, formData, config)
92
+ },
93
+ async show (id: UrlType, config?: AxiosRequestConfig) {
94
+ const u = makeUrl(id)
95
+ return axios().get(u, config)
96
+ // return typeof id === 'boolean' ? u : axios().get(u, config)
97
+ },
98
+ async staticShow (id: UrlType, config?: AxiosRequestConfig) {
99
+ // const m = baseUrl ? baseUrl.toString().split('/').pop() : ''
100
+ // const u = 'Static' + (m ? `/${m}` : '') + `/${id}`
101
+ const u = `Static${baseUrl ? `/${baseUrl}` : ''}` + `/${id}`
102
+ // if (typeof id === 'boolean') {
103
+ // return u
104
+ // }
105
+ return axios().get(u, config)
106
+ },
107
+ async update (id: UrlType, data?: ParamsType, config?: AxiosRequestConfig) {
108
+ const u = makeUrl(id)
109
+ // if (typeof id === 'boolean') {
110
+ // return u
111
+ // }
112
+ const formData = new FormData()
113
+ formData.append('_method', 'put')
114
+ data && Helpers.appendArray(formData, data)
115
+ return axios().post(u, formData, config)
116
+ },
117
+ async destroy (id: UrlType, config?: AxiosRequestConfig) {
118
+ const u = makeUrl(id)
119
+ return axios().delete(u, config)
120
+ // return typeof id === 'boolean' ? u : axios().delete(u, config)
121
+ },
122
+ async destroyAll (ids?: UrlType[], config?: AxiosRequestConfig) {
123
+ const u = makeUrl('DestroyAll')
124
+ return axios().post(u, { ids: (ids || []) }, config)
125
+ },
126
+ getUploadAttachmentsUrl: (id: UrlType) => makeUrl(`${id}/Attachment/Upload`),
127
+ async uploadAttachments (id: UrlType, data: Record<string, any>, config?: AxiosRequestConfig) {
128
+ const _url = makeUrl(`${id}/Attachment/Upload`)
129
+ return axios().post(_url, data, config)
130
+ },
131
+ async deleteAttachment (id: UrlType, fileId: string | number, config?: AxiosRequestConfig) {
132
+ const _url = makeUrl(`${id}/Attachment/${fileId}/Delete`)
133
+ return axios().delete(_url, config)
134
+ },
135
+ async updateAttachment (id: UrlType, fileId: string | number, data: Record<string, any>, config?: AxiosRequestConfig) {
136
+ const _url = makeUrl(`${id}/Attachment/${fileId}/Update`)
137
+ return axios().post(_url, data, config)
138
+ }
139
+ }
140
+ },
141
+ StubUrl: (group?: UrlType): ((segments?: UrlType, parent?: UrlType) => string) => (
142
+ segments?: UrlType,
143
+ parent?: UrlType
144
+ ): string => ((parent ?? '') + (parent && group ? '/' : '')) + (group ?? '') + ((group && segments ? '/' : '') + (segments ?? '')),
145
+ findBy (search: any, value: any, column: string | number = 'id') {
146
+ return lodash.find(search, (e: any) => lodash.isPlainObject(e) ? e[column] === value : e === value)
147
+ },
148
+ // queryStringify: (v: never) => new URLSearchParams(qs.stringify(v, {
149
+ // arrayFormat: 'indices'
150
+ // // encodeValuesOnly: true,
151
+ // // encode: false,
152
+ // })),
153
+ /**
154
+ * Open unique window popup of application
155
+ *
156
+ * @param url
157
+ * @param reject
158
+ * @param windowFeatures
159
+ */
160
+ openWindow<F extends (...args: any[]) => any> (url: string, reject?: F, windowFeatures?: object) {
161
+ return openURL(url, reject, windowFeatures)
162
+ },
163
+ /**
164
+ * Customized helper to download blob from axios response
165
+ * @param response
166
+ * @param callback
167
+ */
168
+ downloadFromResponse (response: any, callback?: ((url: string, response: any) => void)) {
169
+ return new Promise<DownloadFromResponse>((resolve, reject) => {
170
+ const rejectPromise = (e?: { code: DownloadFromResponseCode }) => reject(e ?? { status: !1, code: 'unknown' })
171
+ const resolvePromise = (response: DownloadFromResponse['response']) => resolve({ status: !0, response })
172
+ try {
173
+ if (!response) {
174
+ rejectPromise({ code: 'no_response' })
175
+ return
176
+ }
177
+
178
+ if (response?.data?.data?.url) {
179
+ const url = response?.data?.data?.url
180
+ if (callback) {
181
+ callback(url, response)
182
+ resolvePromise(response)
183
+ return
184
+ }
185
+ const elm = document.createElement('a')
186
+ elm.setAttribute('href', url)
187
+ elm.setAttribute('target', '_blank')
188
+ document.body.appendChild(elm)
189
+ elm.click()
190
+ resolvePromise(response)
191
+ return
192
+ }
193
+
194
+ const name = (response.headers['content-disposition'] || '').split('filename=').pop().replace(/^"+|"+$/g, '')
195
+ if (!name) {
196
+ rejectPromise({ code: 'no_file_name' })
197
+ return
198
+ }
199
+ const file = new Blob([response.data])
200
+ const fileURL = window.URL.createObjectURL(file)
201
+ const fileLink = document.createElement('a')
202
+ if (!fileLink || !fileURL) {
203
+ rejectPromise({ code: 'no_file_url' })
204
+ return
205
+ }
206
+
207
+ fileLink.href = fileURL
208
+ fileLink.setAttribute('download', name)
209
+ document.body.appendChild(fileLink)
210
+ fileLink.click()
211
+ resolvePromise(response)
212
+ setTimeout(() => {
213
+ try {
214
+ document.body.removeChild(fileLink)
215
+ URL.revokeObjectURL(fileURL)
216
+ } catch (e: any) {
217
+ console.log(e)
218
+ if (e?.message) {
219
+ alert(e.message)
220
+ }
221
+ }
222
+ }, 3000)
223
+ } catch (e: any) {
224
+ console.log(e)
225
+ rejectPromise(e)
226
+ }
227
+ })
228
+ },
229
+ async scrollToElement (el: HTMLElement | string, opt?: { target?: HTMLElement | string, duration?: number; }) {
230
+ await nextTick()
231
+ const { getScrollTarget, setVerticalScrollPosition, getVerticalScrollPosition } = scroll
232
+ const scrollTo = typeof el === 'string' ? document.querySelector(el) as HTMLElement : el
233
+ if (!scrollTo) {
234
+ return
235
+ }
236
+ await nextTick()
237
+ const { target: t } = opt || {}
238
+ const targetSelector = typeof t === 'string' ? document.querySelector(t) as HTMLElement : t
239
+ const target = getScrollTarget(scrollTo, targetSelector || window.document.documentElement)
240
+ // console.log(targetSelector, target)
241
+ // let offset = 0
242
+ // try {
243
+ // let parent = scrollTo
244
+ // do {
245
+ // // console.log(parent.getBoundingClientRect().top)
246
+ // offset += parent?.offsetTop || 0
247
+ // parent = parent.offsetParent as HTMLElement
248
+ // } while (parent?.offsetParent)
249
+ // } catch (e) {
250
+ // offset = scrollTo?.offsetTop || 0
251
+ // }
252
+ // offset = scrollTo.getBoundingClientRect().top
253
+ const current = getVerticalScrollPosition(target)
254
+ // console.log(current, target)
255
+ // const offset = scrollTo.getBoundingClientRect().top
256
+ const duration = opt?.duration || 1000
257
+
258
+ let offset = 0
259
+ let parent = scrollTo
260
+ try {
261
+ do {
262
+ offset = parent.getBoundingClientRect().top
263
+ if (offset === 0 && !parent.parentElement) {
264
+ offset = parent.scrollTop
265
+ break
266
+ } else if (offset !== 0 && parent.parentElement) {
267
+ break
268
+ }
269
+ parent = parent.parentElement as HTMLElement
270
+ } while (parent)
271
+ } catch (e) {
272
+ console.log(e)
273
+ offset = scrollTo?.offsetTop || 0
274
+ }
275
+ // console.log(offset, parent, current)
276
+ // const position = offset
277
+ // if (offset > current) {
278
+ // position = (current - offset) + current
279
+ // } else if (offset < current) {
280
+ // position = current + offset
281
+ // }
282
+ // console.log({
283
+ // target,
284
+ // scrollTo,
285
+ // position,
286
+ // offset,
287
+ // current
288
+ // })
289
+ setVerticalScrollPosition(target, (offset + current) - 100, duration)
290
+ },
291
+ async scrollToElementFromErrors (errors?: Partial<Record<string, string[] | string | null | undefined>>, elm?: any, target?: any) {
292
+ if (!errors) {
293
+ return
294
+ }
295
+ for (const [name, value] of Object.entries(errors)) {
296
+ const val = value && Array.isArray(value) ? value[0] : value
297
+ if (val?.toString?.()?.length) {
298
+ if (!elm) {
299
+ const selector = `[data-input-name='${name}']`
300
+ const e = document.querySelector(selector) as HTMLElement
301
+ // console.log(e)
302
+ await this.scrollToElement(e || `[name='${name}']`, { target })
303
+ } else {
304
+ await this.scrollToElement(elm, { target })
305
+ }
306
+ break
307
+ }
308
+ }
309
+ },
310
+ makeUrl (path: string) {
311
+ path = path || ''
312
+ if (path.slice(0, 1) === '/') {
313
+ path = path.slice(1)
314
+ }
315
+ if (window) {
316
+ const l = window.location
317
+ return `${l.protocol}//${l.host}/${path}`
318
+ }
319
+ return `//${path}`
320
+ }
321
+ }