quasar-ui-sellmate-ui-kit 3.4.3 → 3.5.1

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": "quasar-ui-sellmate-ui-kit",
3
- "version": "3.4.3",
3
+ "version": "3.5.1",
4
4
  "author": "Sellmate Dev Team <dev@sellmate.co.kr>",
5
5
  "description": "Sellmate UI Kit",
6
6
  "license": "MIT",
@@ -34,6 +34,7 @@
34
34
  "@quasar/extras": "^1.16.9",
35
35
  "@quasar/quasar-app-extension-testing-unit-vitest": "1.0.0",
36
36
  "@rollup/plugin-buble": "^0.21.3",
37
+ "@rollup/plugin-commonjs": "^21.1.0",
37
38
  "@rollup/plugin-json": "^4.0.0",
38
39
  "@rollup/plugin-node-resolve": "^11.2.1",
39
40
  "@rollup/plugin-replace": "^2.4.2",
@@ -55,6 +56,7 @@
55
56
  "eslint-plugin-vue": "^9.20.1",
56
57
  "fs-extra": "^8.1.0",
57
58
  "happy-dom": "^13.6.2",
59
+ "interactjs": "^1.10.27",
58
60
  "open": "^7.3.0",
59
61
  "postcss": "^8.1.9",
60
62
  "prettier": "^3.2.4",
@@ -86,6 +88,7 @@
86
88
  "last 4 iOS versions"
87
89
  ],
88
90
  "dependencies": {
91
+ "@interactjs/inertia": "^1.10.27",
89
92
  "material-icons": "^1.13.12",
90
93
  "sass": "^1.70.0"
91
94
  }
@@ -7,7 +7,7 @@
7
7
  }"
8
8
  :min-height="`${minHeight}px`"
9
9
  :max-height="maxHeight != null ? `${maxHeight}px` : null"
10
- paragraph-tag="div"
10
+ paragraph-tag="p"
11
11
  v-bind="$attrs"
12
12
  :definitions="toolDefinitions"
13
13
  :toolbar="toolbarDefinitions"
@@ -24,7 +24,7 @@
24
24
  <q-input
25
25
  class="bg-white font-12-400"
26
26
  style="width: 352px"
27
- v-model="value"
27
+ v-model="imgValue"
28
28
  dense
29
29
  outlined
30
30
  type="textarea"
@@ -47,10 +47,11 @@
47
47
  </q-btn>
48
48
  </template>
49
49
  </q-editor>
50
+ {{ model }}
50
51
  </template>
51
52
 
52
53
  <script>
53
- import { defineComponent, ref, watch, computed } from 'vue';
54
+ import { defineComponent, ref, watch, computed, onMounted } from 'vue';
54
55
  import {
55
56
  extend,
56
57
  QCard,
@@ -62,6 +63,7 @@
62
63
  QBtn,
63
64
  useQuasar,
64
65
  } from 'quasar';
66
+ import resizeImage from '../composables/resizable';
65
67
 
66
68
  export default defineComponent({
67
69
  name: 'SEditor',
@@ -133,11 +135,72 @@
133
135
  },
134
136
  setup(props, { emit }) {
135
137
  const model = ref(props.modelValue);
138
+ const editorRef = ref(null);
139
+
140
+ // delete handler element
141
+ function unwrapImg() {
142
+ const contentEl = editorRef.value.getContentEl();
143
+ const resizeHandler = contentEl.querySelectorAll('.img-resize-handler');
144
+
145
+ resizeHandler.forEach(div => {
146
+ const img = div.querySelector('img');
147
+ const parentParagraph = div.parentNode;
148
+ parentParagraph.replaceChild(img, div);
149
+ });
150
+
151
+ model.value = contentEl.innerHTML;
152
+ }
153
+
154
+ // create handler element & resize event
155
+ function wrapImgWithDiv(targetImg) {
156
+ const newDiv = document.createElement('div');
157
+ const className = 'img-resize-handler';
158
+ newDiv.classList.add(className);
159
+ newDiv.style.height = `${targetImg.height}px`;
160
+ newDiv.style.width = `${targetImg.width}px`;
161
+ targetImg.parentNode.insertBefore(newDiv, targetImg);
162
+ newDiv.append(targetImg);
163
+ resizeImage(className);
164
+ }
165
+
166
+ // add click event in contents
167
+ function addImageClickListener() {
168
+ if (!editorRef.value) {
169
+ return;
170
+ }
171
+ const contentEl = editorRef.value.getContentEl();
172
+
173
+ if (!contentEl) {
174
+ return;
175
+ }
176
+
177
+ contentEl.addEventListener('click', event => {
178
+ const images = contentEl.querySelectorAll('img');
179
+ if (!images.length) {
180
+ return;
181
+ }
182
+
183
+ // when clicked, check image document in contents
184
+ if (Array.from(images).some(el => el.contains(event.target))) {
185
+ wrapImgWithDiv(event.target);
186
+ return;
187
+ }
188
+
189
+ unwrapImg();
190
+ });
191
+ }
192
+
193
+ onMounted(() => {
194
+ const contentEl = editorRef.value.getContentEl();
195
+ if (contentEl) {
196
+ addImageClickListener();
197
+ }
198
+ });
199
+
136
200
  const $q = useQuasar();
137
201
 
138
202
  // Toolbar Begin
139
- // const isOpened = ref(false);
140
- const value = ref('');
203
+ const imgValue = ref('');
141
204
 
142
205
  function setFontSize(fontSize) {
143
206
  function isRootNode(node) {
@@ -410,13 +473,13 @@
410
473
  };
411
474
 
412
475
  function onOkClick() {
413
- value.value.split('\n').forEach((el, idx) => {
476
+ imgValue.value.split('\n').forEach((el, idx) => {
414
477
  if (el === '') return;
415
- model.value += `<p><img style="max-width:100%;" src=${el} :alt="image${idx}"/></p>`;
478
+ model.value += `<p><img style="max-width:100%;" src=${el} :alt="image${idx}" /></p>`;
416
479
  });
417
480
 
418
- // isOpened.value = false;
419
- value.value = '';
481
+ addImageClickListener();
482
+ imgValue.value = '';
420
483
  }
421
484
  // Toolbar End
422
485
 
@@ -426,16 +489,14 @@
426
489
  model.value = newValue;
427
490
  },
428
491
  );
429
-
430
492
  watch(
431
493
  () => model.value,
432
- () => {
433
- emit('update:modelValue', model.value);
494
+ newValue => {
495
+ emit('update:modelValue', newValue);
434
496
  },
497
+ { deep: true },
435
498
  );
436
499
 
437
- const editorRef = ref(null);
438
-
439
500
  // https://quasar.dev/vue-components/editor#plaintext-pasting 참조
440
501
  function onPaste(event) {
441
502
  if (event.target.nodeName === 'INPUT') return;
@@ -464,9 +525,8 @@
464
525
  return bar.map(group => group.map(item => (item === 'fontSizes' ? fontSizes : item)));
465
526
  }),
466
527
  toolDefinitions,
467
- // isOpened,
468
528
  model,
469
- value,
529
+ imgValue,
470
530
  onOkClick,
471
531
  onPaste,
472
532
  editorRef,
@@ -495,5 +555,33 @@
495
555
  }
496
556
  }
497
557
  }
558
+ .q-editor__content {
559
+ > p > img {
560
+ display: inline-block;
561
+ }
562
+ .img-resize-handler {
563
+ position: relative;
564
+ background-color: transparent;
565
+ display: inline-block;
566
+ resize: both;
567
+ overflow: hidden;
568
+ &:after {
569
+ content: '';
570
+ position: absolute;
571
+ border: 1px solid;
572
+ width: 100%;
573
+ height: 100%;
574
+ top: 0;
575
+ left: 0;
576
+ }
577
+
578
+ > img {
579
+ display: inline-block;
580
+ object-fit: contain;
581
+ width: 100%;
582
+ height: 100%;
583
+ }
584
+ }
585
+ }
498
586
  }
499
587
  </style>
@@ -0,0 +1,55 @@
1
+ import interact from 'interactjs';
2
+
3
+ function resizeImage(className) {
4
+ interact(`.${className}`)
5
+ .origin('self')
6
+ .resizable({
7
+ // resize from all edges and corners
8
+ edges: { left: true, right: true, bottom: true, top: true },
9
+
10
+ listeners: {
11
+ move(event) {
12
+ const { target } = event
13
+ let x = (parseFloat(target.getAttribute('data-x')) || 0)
14
+ let y = (parseFloat(target.getAttribute('data-y')) || 0)
15
+
16
+ // update the element's style
17
+ target.style.width = `${event.rect.width}px`
18
+ target.style.height = `${event.rect.height}px`
19
+
20
+ // translate when resizing from top or left edges
21
+ x += event.deltaRect.left
22
+ y += event.deltaRect.top
23
+
24
+ target.style.transform = `translate(${x}px,${y}px)`
25
+
26
+ target.setAttribute('data-x', x)
27
+ target.setAttribute('data-y', y)
28
+ const imgEl = target.querySelector('img')
29
+ if (imgEl) {
30
+ imgEl.width = target.style.width.replace('px', '')
31
+ imgEl.height = target.style.height.replace('px', '')
32
+ }
33
+ }
34
+ },
35
+ modifiers: [
36
+ // keep the edges inside the parent
37
+ interact.modifiers.restrictEdges({
38
+ outer: 'parent'
39
+ }),
40
+
41
+ interact.modifiers.aspectRatio({
42
+ // make sure the width is always double the height
43
+ ratio: 'preserve',
44
+ // also restrict the size by nesting another modifier
45
+ modifiers: [
46
+ interact.modifiers.restrictSize({ max: 'parent' }),
47
+ ],
48
+ }),
49
+ ],
50
+
51
+ inertia: true
52
+ })
53
+ }
54
+
55
+ export default resizeImage
package/vitest.config.ts CHANGED
@@ -16,6 +16,9 @@ export default defineConfig({
16
16
  'test/vitest/__tests__/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
17
17
  ],
18
18
  },
19
+ rollupoptions: {
20
+ context: 'window',
21
+ },
19
22
  plugins: [
20
23
  vue({
21
24
  template: { transformAssetUrls },