@myissue/vue-website-page-builder 3.3.22 → 3.3.24

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": "@myissue/vue-website-page-builder",
3
- "version": "3.3.22",
3
+ "version": "3.3.24",
4
4
  "description": "Vue 3 page builder component with drag & drop functionality.",
5
5
  "type": "module",
6
6
  "main": "./dist/vue-website-page-builder.umd.cjs",
@@ -103,33 +103,35 @@ watch(
103
103
  <template #content>
104
104
  <!-- FONT SIZES -->
105
105
  <p class="pbx-myPrimaryParagraph pbx-font-medium pbx-py-0 pbx-my-4">Font Appearance</p>
106
- <div class="pbx-my-2 pbx-py-2">
107
- <label class="pbx-myPrimaryInputLabel"> Font Size </label>
108
- <select
109
- v-model="fontBase"
110
- class="pbx-myPrimarySelect"
111
- @change="pageBuilderService.handleFontSizeBase(fontBase)"
112
- >
113
- <option disabled value="">Select</option>
114
- <option v-for="fontSize in tailwindFontSizes.fontBase" :key="fontSize">
115
- {{ fontSize }}
116
- </option>
117
- </select>
118
- </div>
119
106
  <template v-if="false">
120
107
  <div class="pbx-my-2 pbx-py-2">
121
- <label class="pbx-myPrimaryInputLabel"> Font desktop size </label>
108
+ <label class="pbx-myPrimaryInputLabel"> Font Size </label>
122
109
  <select
123
- v-model="fontDesktop"
110
+ v-model="fontBase"
124
111
  class="pbx-myPrimarySelect"
125
- @change="pageBuilderService.handleFontSizeDesktop(fontDesktop)"
112
+ @change="pageBuilderService.handleFontSizeBase(fontBase)"
126
113
  >
127
114
  <option disabled value="">Select</option>
128
- <option v-for="fontSize in tailwindFontSizes.fontDesktop" :key="fontSize">
115
+ <option v-for="fontSize in tailwindFontSizes.fontBase" :key="fontSize">
129
116
  {{ fontSize }}
130
117
  </option>
131
118
  </select>
132
119
  </div>
120
+ </template>
121
+ <div class="pbx-my-2 pbx-py-2">
122
+ <label class="pbx-myPrimaryInputLabel"> Font size </label>
123
+ <select
124
+ v-model="fontDesktop"
125
+ class="pbx-myPrimarySelect"
126
+ @change="pageBuilderService.handleFontSizeDesktop(fontDesktop)"
127
+ >
128
+ <option disabled value="">Select</option>
129
+ <option v-for="fontSize in tailwindFontSizes.fontDesktop" :key="fontSize">
130
+ {{ fontSize }}
131
+ </option>
132
+ </select>
133
+ </div>
134
+ <template v-if="false">
133
135
  <div class="pbx-my-2 pbx-py-2">
134
136
  <label class="pbx-myPrimaryInputLabel"> Font tablet size </label>
135
137
  <select
@@ -158,36 +160,38 @@ watch(
158
160
  </div>
159
161
  </template>
160
162
  <hr />
161
- <!-- FONT FAMILY -->
163
+
162
164
  <div class="pbx-my-2 pbx-py-2">
163
- <label class="pbx-myPrimaryInputLabel"> Font family </label>
165
+ <label class="pbx-myPrimaryInputLabel"> Font weight </label>
164
166
  <select
165
- v-model="fontFamily"
167
+ v-model="fontWeight"
166
168
  class="pbx-myPrimarySelect"
167
- @change="pageBuilderService.handleFontFamily(fontFamily)"
169
+ @change="pageBuilderService.handleFontWeight(fontWeight)"
168
170
  >
169
171
  <option disabled value="">Select</option>
170
- <option v-for="fontFamily in tailwindFontStyles.fontFamily" :key="fontFamily">
171
- {{ fontFamily }}
172
+ <option v-for="fontWeight in tailwindFontStyles.fontWeight" :key="fontWeight">
173
+ {{ fontWeight }}
172
174
  </option>
173
175
  </select>
174
176
  </div>
175
177
  <hr />
176
178
 
179
+ <!-- FONT FAMILY -->
177
180
  <div class="pbx-my-2 pbx-py-2">
178
- <label class="pbx-myPrimaryInputLabel"> Font weight </label>
181
+ <label class="pbx-myPrimaryInputLabel"> Font family </label>
179
182
  <select
180
- v-model="fontWeight"
183
+ v-model="fontFamily"
181
184
  class="pbx-myPrimarySelect"
182
- @change="pageBuilderService.handleFontWeight(fontWeight)"
185
+ @change="pageBuilderService.handleFontFamily(fontFamily)"
183
186
  >
184
187
  <option disabled value="">Select</option>
185
- <option v-for="fontWeight in tailwindFontStyles.fontWeight" :key="fontWeight">
186
- {{ fontWeight }}
188
+ <option v-for="fontFamily in tailwindFontStyles.fontFamily" :key="fontFamily">
189
+ {{ fontFamily }}
187
190
  </option>
188
191
  </select>
189
192
  </div>
190
193
  <hr />
194
+
191
195
  <div class="pbx-my-2 pbx-py-2">
192
196
  <label class="pbx-myPrimaryInputLabel"> Font Style </label>
193
197
  <select
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { computed } from 'vue'
2
+ import { computed, ref, watch, nextTick } from 'vue'
3
3
  import { sharedPageBuilderStore } from '../../../stores/shared-store'
4
4
  import ClassEditor from './Editables/ClassEditor.vue'
5
5
  import ImageEditor from './Editables/ImageEditor.vue'
@@ -38,6 +38,30 @@ const isHeadingElement = computed(() => {
38
38
  getElement.value instanceof HTMLImageElement
39
39
  )
40
40
  })
41
+
42
+ const scrollContainer = ref(null)
43
+ let lastScrollTop = 0
44
+
45
+ // Watch for changes that cause re-render (e.g. dropdown value in store)
46
+ watch(
47
+ // or the specific value that triggers re-render
48
+ () => pageBuilderStateStore.getElement,
49
+ () => {
50
+ // Restore scroll after DOM updates
51
+ nextTick(() => {
52
+ if (scrollContainer.value) {
53
+ scrollContainer.value.scrollTop = lastScrollTop
54
+ }
55
+ })
56
+ },
57
+ )
58
+
59
+ // Save scroll position before update
60
+ function onScroll() {
61
+ if (scrollContainer.value) {
62
+ lastScrollTop = scrollContainer.value.scrollTop
63
+ }
64
+ }
41
65
  </script>
42
66
 
43
67
  <template>
@@ -58,7 +82,12 @@ const isHeadingElement = computed(() => {
58
82
  </p>
59
83
  </div>
60
84
 
61
- <div class="pbx-pl-3 pbx-pr-3 pbx-mb-4 pbx-overflow-y-scroll">
85
+ <div
86
+ v
87
+ ref="scrollContainer"
88
+ @scroll="onScroll"
89
+ class="pbx-pl-3 pbx-pr-3 pbx-mb-4 pbx-overflow-y-scroll"
90
+ >
62
91
  <div v-show="getElement && pageBuilderService.isEditableElement(getElement)">
63
92
  <article class="pbx-mb-1">
64
93
  <ImageEditor> </ImageEditor>
@@ -720,7 +720,7 @@ onMounted(async () => {
720
720
 
721
721
  <div
722
722
  id="contains-pagebuilder"
723
- class="pbx-pl-4 pbx-pr-4 pbx-pb-4 pbx-pt-1 pbx-bg-black pbx-flex pbx-flex-col pbx-h-full pbx-overflow-y-auto"
723
+ class="pbx-pl-4 pbx-pr-4 pbx-pb-4 pbx-pt-1 pbx-h-full pbx-overflow-y-auto"
724
724
  >
725
725
  <div id="pagebuilder">
726
726
  <div ref="draggableZone">
@@ -24,6 +24,9 @@ import { isEmptyObject } from '../helpers/isEmptyObject'
24
24
 
25
25
  export class PageBuilderService {
26
26
  // Class properties with types
27
+ private fontSizeRegex =
28
+ /^(sm:|md:|lg:|xl:|2xl:)?pbx-text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/
29
+
27
30
  private pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>
28
31
  private getLocalStorageItemName: ComputedRef<string | null>
29
32
  private getApplyImageToSelection: ComputedRef<ImageObject>
@@ -289,10 +292,7 @@ export class PageBuilderService {
289
292
  ) {
290
293
  this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
291
294
  }
292
- //
293
- //
294
- //
295
- //
295
+
296
296
  if (config && formType === 'update') {
297
297
  if (this.pendingMountData) {
298
298
  this.#completeBuilderInitialization(this.pendingMountData)
@@ -306,10 +306,6 @@ export class PageBuilderService {
306
306
  return
307
307
  }
308
308
 
309
- //
310
- //
311
- //
312
- //
313
309
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
314
310
  await nextTick()
315
311
  // Attach event listeners to all editable elements in the Builder
@@ -327,10 +323,6 @@ export class PageBuilderService {
327
323
  return
328
324
  }
329
325
 
330
- //
331
- //
332
- //
333
- //
334
326
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
335
327
  await nextTick()
336
328
  // Attach event listeners to all editable elements in the Builder
@@ -454,11 +446,12 @@ export class PageBuilderService {
454
446
  }
455
447
 
456
448
  #applyElementClassChanges(
457
- selectedCSS: string | undefined,
449
+ cssUserSelection: string | undefined,
458
450
  CSSArray: string[],
459
451
  mutationName: string,
460
452
  ): string | undefined {
461
453
  const currentHTMLElement = this.getElement.value
454
+
462
455
  if (!currentHTMLElement) return
463
456
 
464
457
  const currentCSS = CSSArray.find((CSS) => {
@@ -468,25 +461,29 @@ export class PageBuilderService {
468
461
  // set to 'none' if undefined
469
462
  let elementClass = currentCSS || 'none'
470
463
 
471
- // If selectedCSS is undefined, just set the current state and return
472
- if (selectedCSS === undefined) {
464
+ // If cssUserSelection is undefined, just set the current state and return
465
+ if (cssUserSelection === undefined) {
473
466
  if (typeof mutationName === 'string' && mutationName.length > 2) {
474
467
  ;(this.pageBuilderStateStore as any)[mutationName](elementClass)
475
468
  }
476
469
  return currentCSS
477
470
  }
478
471
 
479
- // selectedCSS examples: bg-zinc-200, px-10, rounded-full etc.
480
- if (typeof selectedCSS === 'string' && selectedCSS !== 'none') {
472
+ // cssUserSelection examples: bg-zinc-200, px-10, rounded-full etc.
473
+ if (typeof cssUserSelection === 'string' && cssUserSelection !== 'none') {
481
474
  if (elementClass && currentHTMLElement.classList.contains(elementClass)) {
482
475
  currentHTMLElement.classList.remove(elementClass)
483
476
  }
484
477
 
485
- currentHTMLElement.classList.add(selectedCSS)
486
- elementClass = selectedCSS
487
- } else if (typeof selectedCSS === 'string' && selectedCSS === 'none' && elementClass) {
478
+ currentHTMLElement.classList.add(cssUserSelection)
479
+ elementClass = cssUserSelection
480
+ } else if (
481
+ typeof cssUserSelection === 'string' &&
482
+ cssUserSelection === 'none' &&
483
+ elementClass
484
+ ) {
488
485
  currentHTMLElement.classList.remove(elementClass)
489
- elementClass = selectedCSS
486
+ elementClass = cssUserSelection
490
487
  }
491
488
 
492
489
  // Only call store mutations after all DOM manipulation is complete
@@ -498,6 +495,75 @@ export class PageBuilderService {
498
495
  return currentCSS
499
496
  }
500
497
 
498
+ handleFontWeight(userSelectedFontWeight?: string): void {
499
+ this.#applyElementClassChanges(
500
+ userSelectedFontWeight,
501
+ tailwindFontStyles.fontWeight,
502
+ 'setFontWeight',
503
+ )
504
+ }
505
+
506
+ handleFontSizeBase(userSelectedFontSize?: string): void {
507
+ this.#applyElementClassChanges(userSelectedFontSize, tailwindFontSizes.fontBase, 'setFontBase')
508
+ }
509
+
510
+ handleFontSizeDesktop(userSelectedFontSize?: string): void {
511
+ const currentHTMLElement = this.getElement.value
512
+ if (!currentHTMLElement) return
513
+
514
+ // Hardcoded mapping: selected => base
515
+ const fontSizeBaseMap: Record<string, string> = {
516
+ 'pbx-text-9xl': 'pbx-text-6xl',
517
+ 'pbx-text-8xl': 'pbx-text-6xl',
518
+ 'pbx-text-7xl': 'pbx-text-5xl',
519
+ 'pbx-text-6xl': 'pbx-text-3xl',
520
+ 'pbx-text-5xl': 'pbx-text-3xl',
521
+ 'pbx-text-4xl': 'pbx-text-2xl',
522
+ 'pbx-text-3xl': 'pbx-text-xl',
523
+ 'pbx-text-2xl': 'pbx-text-lg',
524
+ 'pbx-text-xl': 'pbx-text-base',
525
+ 'pbx-text-lg': 'pbx-text-sm',
526
+ 'pbx-text-base': 'pbx-text-xs',
527
+ 'pbx-text-sm': 'pbx-text-xs',
528
+ 'pbx-text-xs': 'pbx-text-xs',
529
+ }
530
+
531
+ if (userSelectedFontSize) {
532
+ // Remove all existing font size classes first
533
+ Array.from(currentHTMLElement.classList).forEach((cls) => {
534
+ if (this.fontSizeRegex.test(cls)) {
535
+ currentHTMLElement.classList.remove(cls)
536
+ }
537
+ })
538
+
539
+ // Extract the font size class (remove 'lg:' if present)
540
+ const fontSizeClass = userSelectedFontSize.replace(/^lg:/, '')
541
+
542
+ const baseClass = fontSizeBaseMap[fontSizeClass] || fontSizeClass
543
+ const lgClass = `lg:${fontSizeClass}`
544
+
545
+ if (baseClass !== fontSizeClass) {
546
+ currentHTMLElement.classList.add(baseClass, lgClass)
547
+ } else {
548
+ currentHTMLElement.classList.add(baseClass)
549
+ }
550
+ }
551
+
552
+ const currentCSS = tailwindFontSizes.fontDesktop.find((CSS) => {
553
+ return currentHTMLElement.classList.contains(CSS)
554
+ })
555
+
556
+ if (!userSelectedFontSize) {
557
+ this.pageBuilderStateStore.setFontDesktop('none')
558
+ }
559
+
560
+ if (currentCSS && !userSelectedFontSize) {
561
+ this.pageBuilderStateStore.setFontDesktop(currentCSS)
562
+ }
563
+
564
+ return currentCSS
565
+ }
566
+
501
567
  #applyHelperCSSToElements(element: HTMLElement): void {
502
568
  this.#wrapElementInDivIfExcluded(element)
503
569
 
@@ -505,14 +571,43 @@ export class PageBuilderService {
505
571
  element.classList.add('smooth-transition')
506
572
  }
507
573
 
508
- // Add padding to DIV
509
- if (element.tagName === 'DIV') {
510
- if (element.classList.length === 0) {
511
- // element.classList.add("p-2");
574
+ // If this is a DIV and its only/main child is a heading, apply font size classes to the DIV
575
+ if (
576
+ element.tagName === 'DIV' &&
577
+ element.children.length === 1 &&
578
+ ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(element.children[0].tagName)
579
+ ) {
580
+ const heading = element.children[0] as HTMLElement
581
+
582
+ element.classList.forEach((cls) => {
583
+ if (this.fontSizeRegex.test(cls)) {
584
+ element.classList.remove(cls)
585
+ }
586
+ })
587
+
588
+ // Apply responsive font size classes based on heading type
589
+ if (heading.tagName === 'H2') {
590
+ element.classList.add('pbx-text-3xl', 'lg:pbx-text-6xl')
591
+ }
592
+ if (heading.tagName === 'H3') {
593
+ element.classList.add('pbx-text-2xl', 'lg:pbx-text-4xl')
512
594
  }
513
595
  }
514
596
  }
515
597
 
598
+ async toggleTipTapModal(status: boolean): Promise<void> {
599
+ this.pageBuilderStateStore.setShowModalTipTap(status)
600
+
601
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
602
+ await nextTick()
603
+ // Attach event listeners to all editable elements in the Builder
604
+ await this.#addListenersToEditableElements()
605
+
606
+ if (!status) {
607
+ await this.handleAutoSave()
608
+ }
609
+ }
610
+
516
611
  #wrapElementInDivIfExcluded(element: HTMLElement): void {
517
612
  if (!element) return
518
613
 
@@ -792,13 +887,6 @@ export class PageBuilderService {
792
887
  }
793
888
  }
794
889
 
795
- handleFontWeight(userSelectedFontWeight?: string): void {
796
- this.#applyElementClassChanges(
797
- userSelectedFontWeight,
798
- tailwindFontStyles.fontWeight,
799
- 'setFontWeight',
800
- )
801
- }
802
890
  handleFontFamily(userSelectedFontFamily?: string): void {
803
891
  this.#applyElementClassChanges(
804
892
  userSelectedFontFamily,
@@ -915,17 +1003,6 @@ export class PageBuilderService {
915
1003
  }
916
1004
  // border radius / end
917
1005
 
918
- handleFontSizeBase(userSelectedFontSize?: string): void {
919
- this.#applyElementClassChanges(userSelectedFontSize, tailwindFontSizes.fontBase, 'setFontBase')
920
- }
921
-
922
- handleFontSizeDesktop(userSelectedFontSize?: string): void {
923
- this.#applyElementClassChanges(
924
- userSelectedFontSize,
925
- tailwindFontSizes.fontDesktop,
926
- 'setFontDesktop',
927
- )
928
- }
929
1006
  handleFontSizeTablet(userSelectedFontSize?: string): void {
930
1007
  this.#applyElementClassChanges(
931
1008
  userSelectedFontSize,
@@ -2063,19 +2140,6 @@ export class PageBuilderService {
2063
2140
  }
2064
2141
  }
2065
2142
 
2066
- async toggleTipTapModal(status: boolean): Promise<void> {
2067
- this.pageBuilderStateStore.setShowModalTipTap(status)
2068
-
2069
- // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
2070
- await nextTick()
2071
- // Attach event listeners to all editable elements in the Builder
2072
- await this.#addListenersToEditableElements()
2073
-
2074
- if (!status) {
2075
- await this.handleAutoSave()
2076
- }
2077
- }
2078
-
2079
2143
  async initializeElementStyles(): Promise<void> {
2080
2144
  // Wait for Vue to finish DOM updates before attaching event listeners.
2081
2145
  // This ensure elements exist in the DOM.
package/src/css/app.css CHANGED
@@ -366,13 +366,6 @@ a {
366
366
  @apply pbx-text-myPrimaryLinkColor;
367
367
  }
368
368
 
369
- h2 {
370
- @apply pbx-text-3xl pbx-mt-4 pbx-mb-3 pbx-font-medium;
371
- }
372
- h3 {
373
- @apply pbx-text-2xl pbx-mt-4 pbx-mb-3 pbx-font-medium;
374
- }
375
-
376
369
  /* CSS for content inside page builder # start */
377
370
  #page-builder-editor .tiptap {
378
371
  outline: none !important;