@mythpe/quasar-ui-qui 0.0.27-dev → 0.0.28-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mythpe/quasar-ui-qui",
3
- "version": "0.0.27-dev",
3
+ "version": "0.0.28-dev",
4
4
  "description": "MyTh Quasar UI Kit App Extension",
5
5
  "author": {
6
6
  "name": "MyTh Ahmed Faiz",
@@ -24,9 +24,11 @@
24
24
  "build:css": "node build/script.css.js"
25
25
  },
26
26
  "dependencies": {
27
+ "@ckeditor/ckeditor5-vue": "^7.3.0",
27
28
  "@vee-validate/i18n": "^4.14.0",
28
29
  "@vee-validate/rules": "^4.14.0",
29
30
  "axios": "^1.7.8",
31
+ "ckeditor5": "^43.3.1",
30
32
  "lodash": "^4.17.0",
31
33
  "lodash-inflection": "^1.5.0",
32
34
  "typed.js": "^2.1.0",
@@ -0,0 +1,403 @@
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 { MCkeditorProps as Props } from '../../types'
16
+ import { computed, reactive, toValue, useTemplateRef } from 'vue'
17
+ import { useBindInput, useMyth } from '../../composable'
18
+
19
+ import type {
20
+ Alignment,
21
+ Autoformat,
22
+ Base64UploadAdapter,
23
+ BlockQuote,
24
+ Bold,
25
+ CKFinder,
26
+ CKFinderUploadAdapter,
27
+ ClassicEditor,
28
+ CloudServices,
29
+ Code,
30
+ CodeBlock,
31
+ EditorConfig,
32
+ Essentials,
33
+ FontBackgroundColor,
34
+ FontColor,
35
+ FontFamily,
36
+ FontSize,
37
+ Heading,
38
+ Image,
39
+ ImageCaption,
40
+ ImageResize,
41
+ ImageStyle,
42
+ ImageToolbar,
43
+ ImageUpload,
44
+ Indent,
45
+ IndentBlock,
46
+ Italic,
47
+ Link,
48
+ List,
49
+ MediaEmbed,
50
+ Mention,
51
+ Paragraph,
52
+ PasteFromOffice,
53
+ PictureEditing,
54
+ RemoveFormat,
55
+ SourceEditing,
56
+ Strikethrough,
57
+ Subscript,
58
+ Superscript,
59
+ Table,
60
+ TableColumnResize,
61
+ TableToolbar,
62
+ TextTransformation,
63
+ TodoList,
64
+ Underline
65
+ } from 'ckeditor5'
66
+ import { Ckeditor } from '@ckeditor/ckeditor5-vue'
67
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
68
+ // @ts-ignore
69
+ import arTranslations from 'ckeditor5/translations/ar.js'
70
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
71
+ // @ts-ignore
72
+ import enTranslations from 'ckeditor5/translations/en.js'
73
+
74
+ type P = {
75
+ name: Props['name'];
76
+ lang: Props['lang'];
77
+ config?: Props['config'];
78
+ tagName?: Props['tagName'];
79
+ disabled?: Props['disabled'];
80
+ disableTwoWayDataBinding?: Props['disableTwoWayDataBinding'];
81
+
82
+ auto?: Props['auto'];
83
+ col?: Props['col'];
84
+ xs?: Props['xs'];
85
+ sm?: Props['sm'];
86
+ md?: Props['md'];
87
+ lg?: Props['lg'];
88
+ xl?: Props['xl'];
89
+ label?: Props['label'];
90
+ caption?: Props['caption'];
91
+ help?: Props['help'];
92
+ required?: Props['required'];
93
+ rules?: Props['rules'];
94
+ viewMode?: Props['viewMode'];
95
+ viewModeValue?: Props['viewModeValue'];
96
+ fieldOptions?: Props['fieldOptions'];
97
+ }
98
+ const props = withDefaults(defineProps<P>(), {
99
+ name: () => '',
100
+ lang: () => 'ar',
101
+ config: undefined,
102
+ tagName: () => 'div',
103
+ disabled: () => !1,
104
+ disableTwoWayDataBinding: () => !1,
105
+
106
+ auto: undefined,
107
+ col: undefined,
108
+ xs: undefined,
109
+ sm: undefined,
110
+ md: undefined,
111
+ lg: undefined,
112
+ xl: undefined,
113
+ label: undefined,
114
+ caption: undefined,
115
+ help: undefined,
116
+ required: undefined,
117
+ rules: undefined,
118
+ viewMode: () => !1,
119
+ viewModeValue: undefined,
120
+ fieldOptions: undefined
121
+ })
122
+ defineModel<Props['modelValue']>({ required: !1, default: undefined })
123
+ const { __, mOptions } = useMyth()
124
+ const helper = useBindInput<any>(() => props, 'ckeditor')
125
+ const { getLabel, inputRules } = helper
126
+ const inputScope = useField<Props['modelValue']>(() => props.name, inputRules, {
127
+ validateOnMount: !1,
128
+ validateOnValueUpdate: !1,
129
+ syncVModel: !0,
130
+ label: getLabel,
131
+ ...toValue<any>(props.fieldOptions)
132
+ })
133
+ const { value, errorMessage, handleChange } = inputScope
134
+
135
+ const isRtl = computed(() => props.lang === 'ar')
136
+ const getConfig = computed<EditorConfig>(() => {
137
+ const inpConfig = {
138
+ language: {
139
+ ui: props.lang as string,
140
+ content: props.lang as string,
141
+ textPartLanguage: [
142
+ {
143
+ title: __('ar'),
144
+ languageCode: 'ar',
145
+ textDirection: 'rtl'
146
+ },
147
+ {
148
+ title: __('en'),
149
+ languageCode: 'en',
150
+ textDirection: 'ltr'
151
+ }
152
+ ]
153
+ },
154
+ translations: [
155
+ arTranslations,
156
+ enTranslations
157
+ ],
158
+ plugins: [
159
+ Autoformat,
160
+ BlockQuote,
161
+ Bold,
162
+ CKFinder,
163
+ CKFinderUploadAdapter,
164
+ CloudServices,
165
+ Essentials,
166
+ Heading,
167
+ Image,
168
+ ImageCaption,
169
+ ImageResize,
170
+ ImageStyle,
171
+ ImageToolbar,
172
+ ImageUpload,
173
+ Base64UploadAdapter,
174
+ Indent,
175
+ IndentBlock,
176
+ Italic,
177
+ Link,
178
+ List,
179
+ MediaEmbed,
180
+ Mention,
181
+ Paragraph,
182
+ PasteFromOffice,
183
+ PictureEditing,
184
+ Table,
185
+ TableColumnResize,
186
+ TableToolbar,
187
+ TextTransformation,
188
+ Underline,
189
+ FontSize,
190
+ FontFamily,
191
+ FontColor,
192
+ FontBackgroundColor,
193
+ RemoveFormat,
194
+ Strikethrough,
195
+ Subscript,
196
+ Code,
197
+ CodeBlock,
198
+ Alignment,
199
+ Superscript,
200
+ TodoList,
201
+ SourceEditing
202
+ ],
203
+ toolbar: {
204
+ items: [
205
+ 'undo',
206
+ 'redo',
207
+ '|',
208
+ 'bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript', 'code',
209
+ '|',
210
+ 'fontfamily', 'fontsize', 'fontColor', 'fontBackgroundColor',
211
+ '|',
212
+ 'alignment',
213
+ 'insertTable',
214
+ 'heading',
215
+ '|',
216
+ 'link', 'uploadImage', 'blockQuote', 'codeBlock',
217
+ '|',
218
+ 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent',
219
+ '|',
220
+ // 'ckbox',
221
+ 'removeFormat',
222
+ 'mediaEmbed',
223
+ '|',
224
+ 'sourceEditing'
225
+ ],
226
+ shouldNotGroupWhenFull: true
227
+ },
228
+ heading: {
229
+ options: [
230
+ {
231
+ model: 'paragraph',
232
+ title: 'Paragraph',
233
+ class: 'ck-heading_paragraph'
234
+ },
235
+ {
236
+ model: 'heading1',
237
+ view: 'h1',
238
+ title: 'Heading 1',
239
+ class: 'ck-heading_heading1'
240
+ },
241
+ {
242
+ model: 'heading2',
243
+ view: 'h2',
244
+ title: 'Heading 2',
245
+ class: 'ck-heading_heading2'
246
+ },
247
+ {
248
+ model: 'heading3',
249
+ view: 'h3',
250
+ title: 'Heading 3',
251
+ class: 'ck-heading_heading3'
252
+ },
253
+ {
254
+ model: 'heading4',
255
+ view: 'h4',
256
+ title: 'Heading 4',
257
+ class: 'ck-heading_heading4'
258
+ }
259
+ ]
260
+ },
261
+ image: {
262
+ resizeOptions: [
263
+ {
264
+ name: 'resizeImage:original',
265
+ label: 'Default image width',
266
+ value: null
267
+ },
268
+ {
269
+ name: 'resizeImage:50',
270
+ label: '50% page width',
271
+ value: '50'
272
+ },
273
+ {
274
+ name: 'resizeImage:75',
275
+ label: '75% page width',
276
+ value: '75'
277
+ }
278
+ ],
279
+ toolbar: [
280
+ 'imageTextAlternative',
281
+ 'toggleImageCaption',
282
+ '|',
283
+ 'imageStyle:inline',
284
+ 'imageStyle:wrapText',
285
+ 'imageStyle:breakText',
286
+ '|',
287
+ 'resizeImage'
288
+ ]
289
+ },
290
+ menuBar: {
291
+ isVisible: !1
292
+ },
293
+ link: {
294
+ addTargetToExternalLinks: true,
295
+ defaultProtocol: 'https://'
296
+ },
297
+ table: {
298
+ contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells']
299
+ }
300
+ }
301
+ if (props.config) {
302
+ return props.config(inpConfig as EditorConfig)
303
+ }
304
+ return inpConfig as EditorConfig
305
+ })
306
+ const listeners = {
307
+ 'update:modelValue': (v: Props['modelValue']) => handleChange(v, !!errorMessage.value)
308
+ }
309
+ const input = useTemplateRef<any>('input')
310
+ const scopes = reactive(inputScope)
311
+ defineExpose<typeof scopes & { input: typeof input }>({ input, ...scopes })
312
+ defineOptions({
313
+ name: 'MCkeditor',
314
+ inheritAttrs: !1
315
+ })
316
+ </script>
317
+
318
+ <template>
319
+ <MCol
320
+ :auto="auto"
321
+ :class="[$attrs.class,{'m--input__required':inputRules?.required!==undefined,'m--input__error':!!errorMessage,'m--input__view':viewMode}]"
322
+ :col="col"
323
+ :lg="lg"
324
+ :md="md"
325
+ :name="name"
326
+ :sm="sm"
327
+ :xs="xs"
328
+ >
329
+ <slot
330
+ name="top-input"
331
+ v-bind="scopes"
332
+ />
333
+ <slot name="top-label">
334
+ <MInputLabel
335
+ v-if="!!getLabel"
336
+ :field="scopes"
337
+ >
338
+ <MHelpRow
339
+ :text="help"
340
+ tooltip
341
+ />
342
+ </MInputLabel>
343
+ </slot>
344
+ <slot name="caption">
345
+ <div
346
+ v-if="!!caption"
347
+ class="m--input__caption"
348
+ >
349
+ {{ __(caption) }}
350
+ </div>
351
+ </slot>
352
+ <slot
353
+ name="help"
354
+ v-bind="scopes"
355
+ >
356
+ <MHelpRow
357
+ v-if="!getLabel"
358
+ :text="help"
359
+ />
360
+ </slot>
361
+ <MTransition>
362
+ <div
363
+ v-if="!!errorMessage"
364
+ class="text-negative text-caption"
365
+ >
366
+ <q-icon
367
+ v-if="!!errorMessage"
368
+ color="negative"
369
+ name="ion-ios-information-circle-outline"
370
+ size="20px"
371
+ />
372
+ {{ errorMessage }}
373
+ </div>
374
+ </MTransition>
375
+ <div
376
+ v-if="viewMode"
377
+ v-html="value"
378
+ />
379
+ <div
380
+ v-else
381
+ :dir="isRtl ? 'rtl' : 'ltr'"
382
+ :style="`direction: ${isRtl ? 'rtl' : 'ltr'}`"
383
+ v-bind="$attrs"
384
+ >
385
+ <ckeditor
386
+ ref="input"
387
+ :config="getConfig"
388
+ :disable-two-way-data-binding="disableTwoWayDataBinding"
389
+ :disabled="disabled"
390
+ :editor="ClassicEditor"
391
+ :model-value="value || ''"
392
+ :tag-name="tagName"
393
+ v-bind="{...$attrs,...mOptions.ckeditor}"
394
+ v-on="listeners"
395
+ />
396
+ <slot v-bind="scopes" />
397
+ </div>
398
+ <slot
399
+ name="bottom-input"
400
+ v-bind="scopes"
401
+ />
402
+ </MCol>
403
+ </template>
@@ -10,6 +10,7 @@ import MAxios from './MAxios.vue'
10
10
  import MAvatarViewer from './MAvatarViewer.vue'
11
11
  import MBtn from './MBtn.vue'
12
12
  import MCheckbox from './MCheckbox.vue'
13
+ import MCkeditor from './MCkeditor.vue'
13
14
  import MColor from './MColor.vue'
14
15
  import MDate from './MDate.vue'
15
16
  import MEditor from './MEditor.vue'
@@ -38,6 +39,7 @@ export {
38
39
  MAvatarViewer,
39
40
  MBtn,
40
41
  MCheckbox,
42
+ MCkeditor,
41
43
  MColor,
42
44
  MDate,
43
45
  MEditor,
@@ -59,6 +59,7 @@ import {
59
59
  MDtContextmenuItemsProps,
60
60
  MDtContextmenuItemsSlots
61
61
  } from './m-datatable'
62
+ import type { EditorConfig } from 'ckeditor5'
62
63
 
63
64
  export interface MTransitionProps extends TransitionGroupProps {
64
65
  enterIn?: string;
@@ -1154,6 +1155,37 @@ export type MDialogSlots = {
1154
1155
  default: () => VNode[];
1155
1156
  }
1156
1157
 
1158
+ export type MCkeditorProps = Omit<BaseInputsProps, 'hint' | 'topLabel' | 'placeholder' | 'autocomplete'> & {
1159
+ /**
1160
+ * Editor language.
1161
+ * Default value: ar.
1162
+ */
1163
+ lang: 'ar' | 'en';
1164
+ /**
1165
+ * Specifies the configuration of the editor.
1166
+ * https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
1167
+ */
1168
+ config?: ((config: EditorConfig) => EditorConfig) | undefined;
1169
+ /**
1170
+ * By default, the editor component creates a <div> container which is used as an element passed to the editor (for example, ClassicEditor#element).
1171
+ * The element can be configured, so for example to create a <textarea>, use the following directive:
1172
+ * tag-name="textarea"
1173
+ * Default value: div.
1174
+ */
1175
+ tagName?: string;
1176
+ /**
1177
+ * This directive controls the isReadOnly property of the editor.
1178
+ * Default value: false.
1179
+ */
1180
+ disabled?: boolean;
1181
+ /**
1182
+ * Allows disabling the two-way data binding mechanism.
1183
+ * Default value: false.
1184
+ */
1185
+ disableTwoWayDataBinding?: boolean;
1186
+ }
1187
+ export type MCkeditorSlots = BaseInputsSlots
1188
+
1157
1189
  declare module '@vue/runtime-core' {
1158
1190
  interface GlobalComponents {
1159
1191
  // Form.
@@ -1161,6 +1193,7 @@ declare module '@vue/runtime-core' {
1161
1193
  MAxios: GlobalComponentConstructor<MAxiosProps, MAxiosSlots>;
1162
1194
  MBtn: GlobalComponentConstructor<MBtnProps, MBtnSlots>;
1163
1195
  MCheckbox: GlobalComponentConstructor<MCheckboxProps, MCheckboxSlots>;
1196
+ MCkeditor: GlobalComponentConstructor<MCkeditorProps, MCkeditorSlots>;
1164
1197
  MColor: GlobalComponentConstructor<MInputProps, MInputSlots>;
1165
1198
  MDate: GlobalComponentConstructor<MDateProps, MDateSlots>;
1166
1199
  MEditor: GlobalComponentConstructor<MEditorProps, MEditorSlots>;
@@ -2,7 +2,7 @@ import type {
2
2
  MAvatarViewerProps,
3
3
  MBlockProps,
4
4
  MBtnProps,
5
- MCheckboxProps,
5
+ MCheckboxProps, MCkeditorProps,
6
6
  MColProps,
7
7
  MColumnProps,
8
8
  MContainerProps,
@@ -105,6 +105,10 @@ export interface PropsContext {
105
105
  * MCheckbox component.
106
106
  */
107
107
  checkbox?: Partial<MCheckboxProps>;
108
+ /**
109
+ * MCkeditor component.
110
+ */
111
+ ckeditor?: Partial<MCkeditorProps>;
108
112
  /**
109
113
  * MRadio component.
110
114
  */
@@ -286,7 +290,7 @@ export interface PropsContext {
286
290
  btn?: {
287
291
  props?: Partial<QBtnProps>;
288
292
  };
289
- }
293
+ };
290
294
  };
291
295
  }
292
296
 
@@ -15,6 +15,7 @@ import {
15
15
  MBlock,
16
16
  MBtn,
17
17
  MCheckbox,
18
+ MCkeditor,
18
19
  MCol,
19
20
  MColor,
20
21
  MColumn,
@@ -97,6 +98,7 @@ function install (app: App, options: InstallOptions = {}) {
97
98
  app.component('MAxios', MAxios)
98
99
  app.component('MBtn', MBtn)
99
100
  app.component('MCheckbox', MCheckbox)
101
+ app.component('MCkeditor', MCkeditor)
100
102
  app.component('MColor', MColor)
101
103
  app.component('MDate', MDate)
102
104
  app.component('MEditor', MEditor)