@designcrowd/library.brand-page 5.10.19 → 5.10.20-ast-link-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/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +1 -0
- package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +1 -0
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +1 -0
- package/lib/src/brand-page/models/index.d.ts +5 -0
- package/lib/src/brand-page/models/index.js +4 -0
- package/lib/src/brand-page/utils/style.util.d.ts +8 -1
- package/lib/src/brand-page/utils/style.util.js +58 -5
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.js +1 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/page-content-items.d.ts +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/page-content-items.js +2 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +33 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +35 -1
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +1 -0
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +17 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.d.ts +19 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.js +31 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/AutoLink.d.ts +2 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/AutoLink.js +161 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/MaxLength.js +3 -3
- package/lib/src/brand-page-maker/composables/rich-text-editor/font.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/font.js +0 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.js +0 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.d.ts +19 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.js +87 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.js +0 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/textAlign.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/textAlign.js +0 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +24 -3
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +214 -33
- package/lib/src/brand-page-maker/models/button-group.model.d.ts +2 -0
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +19 -2
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +340 -8
- package/lib/src/bundled-translations.de-DE-848cpWPB.js +117 -0
- package/lib/src/{bundled-translations.de-DE-O4sKkzBX.js → bundled-translations.de-DE-DjQFwukR.js} +1 -1
- package/lib/src/{bundled-translations.es-ES-C4lGaf08.js → bundled-translations.es-ES--EbGRI7e.js} +1 -1
- package/lib/src/bundled-translations.es-ES-CtPI5G7I.js +117 -0
- package/lib/src/bundled-translations.fr-FR-BS3Kia5y.js +117 -0
- package/lib/src/{bundled-translations.fr-FR-CIy8KjAV.js → bundled-translations.fr-FR-VtC2JYUC.js} +1 -1
- package/lib/src/bundled-translations.pt-PT-Balnne-7.js +117 -0
- package/lib/src/{bundled-translations.pt-PT-C8EcSdyX.js → bundled-translations.pt-PT-l9cEldEo.js} +1 -1
- package/lib/src/bundles/bundled-translations.de-DE.json +6 -6
- package/lib/src/bundles/bundled-translations.es-ES.json +8 -8
- package/lib/src/bundles/bundled-translations.fr-FR.json +13 -13
- package/lib/src/bundles/bundled-translations.pt-PT.json +2 -2
- package/lib/src/css/library.brand-page-brandCrowd.min.css +101 -75
- package/lib/src/css/library.brand-page-brandPage.min.css +101 -75
- package/lib/src/css/library.brand-page-designCom.min.css +101 -75
- package/lib/src/css/library.brand-page-preview.min.css +101 -75
- package/lib/src/index.d.ts +1 -0
- package/lib/src/index.mjs +30183 -27720
- package/lib/src/lib.js +1 -0
- package/lib/src/mockServiceWorker.js +91 -54
- package/lib/src/shared/content-settings/components/color-field/ColorField.mixin.d.ts +11 -0
- package/lib/src/shared/content-settings/components/color-field/ColorField.mixin.js +5 -0
- package/lib/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.mixin.d.ts +11 -1
- package/lib/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.mixin.js +4 -0
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +2 -0
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.js +12 -7
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +2 -0
- package/package.json +6 -3
- package/src/brand-page/components/banner-section/BannerSection.vue +6 -0
- package/src/brand-page/components/logo/Logo.vue +4 -4
- package/src/brand-page/components/logo/LogoRender.vue +7 -2
- package/src/brand-page/components/text/Text.vue +2 -0
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +31 -11
- package/src/brand-page/models/brand-page-context.model.ts +1 -0
- package/src/brand-page/models/index.ts +6 -0
- package/src/brand-page/utils/style.util.ts +105 -5
- package/src/brand-page-maker/components/action-bar/i18n/action-bar.de-DE.json +1 -1
- package/src/brand-page-maker/components/action-bar/i18n/action-bar.es-ES.json +1 -1
- package/src/brand-page-maker/components/action-bar/i18n/action-bar.fr-FR.json +1 -1
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +1 -1
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.ts +1 -0
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/page-content-items.ts +2 -0
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +44 -1
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +1 -0
- package/src/brand-page-maker/components/brandpage-settings/i18n/brand-page-settings.fr-FR.json +2 -2
- package/src/brand-page-maker/components/brandpage-settings/i18n/brand-page-settings.pt-PT.json +1 -1
- package/src/brand-page-maker/components/google-analytics/i18n/google-analytics.fr-FR.json +1 -1
- package/src/brand-page-maker/components/layout-switcher/i18n/layout-switcher.de-DE.json +1 -1
- package/src/brand-page-maker/components/layout-switcher/i18n/layout-switcher.fr-FR.json +1 -1
- package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.de-DE.json +4 -4
- package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.es-ES.json +4 -4
- package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.fr-FR.json +4 -4
- package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.pt-PT.json +4 -4
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +548 -50
- package/src/brand-page-maker/components/sensitive-content/i18n/sensitive-settings.de-DE.json +4 -4
- package/src/brand-page-maker/components/sensitive-content/i18n/sensitive-settings.es-ES.json +4 -4
- package/src/brand-page-maker/components/sensitive-content/i18n/sensitive-settings.fr-FR.json +4 -4
- package/src/brand-page-maker/components/sensitive-content/i18n/sensitive-settings.pt-PT.json +4 -4
- package/src/brand-page-maker/components/seo-settings/i18n/existing-domain-modal.de-DE.json +12 -12
- package/src/brand-page-maker/components/seo-settings/i18n/existing-domain-modal.es-ES.json +12 -12
- package/src/brand-page-maker/components/seo-settings/i18n/existing-domain-modal.fr-FR.json +12 -12
- package/src/brand-page-maker/components/seo-settings/i18n/existing-domain-modal.pt-PT.json +12 -12
- package/src/brand-page-maker/components/social-share/i18n/social-share.de-DE.json +8 -8
- package/src/brand-page-maker/components/social-share/i18n/social-share.es-ES.json +8 -8
- package/src/brand-page-maker/components/social-share/i18n/social-share.fr-FR.json +8 -8
- package/src/brand-page-maker/components/social-share/i18n/social-share.pt-PT.json +8 -8
- package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -0
- package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.ts +42 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/AutoLink.ts +227 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/MaxLength.test.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/extensions/MaxLength.ts +4 -15
- package/src/brand-page-maker/composables/rich-text-editor/font.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/formatting.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/hyperlink.ts +114 -0
- package/src/brand-page-maker/composables/rich-text-editor/spacing.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/textAlign.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +299 -41
- package/src/brand-page-maker/constants/i18n/constants.de-DE.json +1 -1
- package/src/brand-page-maker/constants/i18n/constants.es-ES.json +3 -3
- package/src/brand-page-maker/convertors/i18n/converter.de-DE.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.es-ES.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.fr-FR.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.pt-PT.json +23 -23
- package/src/brand-page-maker/models/button-group.model.ts +2 -0
- package/src/brand-page-maker/models/i18n/models.es-ES.json +1 -1
- package/src/brand-page-maker/stores/brandpage-maker/__snapshots__/brandpage-maker-store.test.ts.snap +1 -0
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +418 -0
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +470 -25
- package/src/bundles/bundled-translations.de-DE.json +6 -6
- package/src/bundles/bundled-translations.es-ES.json +8 -8
- package/src/bundles/bundled-translations.fr-FR.json +13 -13
- package/src/bundles/bundled-translations.pt-PT.json +2 -2
- package/src/lib.ts +1 -0
- package/src/shared/color-picker/components/i18n/color-picker.de-DE.json +5 -5
- package/src/shared/color-picker/components/i18n/color-picker.es-ES.json +5 -5
- package/src/shared/color-picker/components/i18n/color-picker.fr-FR.json +5 -5
- package/src/shared/color-picker/components/i18n/color-picker.pt-PT.json +5 -5
- package/src/shared/common/i18n/common.de-DE.json +47 -47
- package/src/shared/common/i18n/common.es-ES.json +46 -46
- package/src/shared/common/i18n/common.fr-FR.json +46 -46
- package/src/shared/common/i18n/common.pt-PT.json +46 -46
- package/src/shared/common/i18n/error.de-DE.json +25 -25
- package/src/shared/common/i18n/error.es-ES.json +25 -25
- package/src/shared/common/i18n/error.fr-FR.json +25 -25
- package/src/shared/common/i18n/error.pt-PT.json +25 -25
- package/src/shared/content-settings/components/color-field/ColorField.mixin.ts +5 -0
- package/src/shared/content-settings/components/color-field/ColorField.vue +1 -1
- package/src/shared/content-settings/components/links-field/i18n/links-field.de-DE.json +1 -1
- package/src/shared/content-settings/components/links-field/i18n/links-field.fr-FR.json +1 -1
- package/src/shared/content-settings/components/logo-field/LogoField.vue +0 -1
- package/src/shared/content-settings/components/logo-selection-field/i18n/logo-selection.de-DE.json +5 -5
- package/src/shared/content-settings/components/logo-selection-field/i18n/logo-selection.es-ES.json +5 -5
- package/src/shared/content-settings/components/logo-selection-field/i18n/logo-selection.fr-FR.json +5 -5
- package/src/shared/content-settings/components/logo-selection-field/i18n/logo-selection.pt-PT.json +5 -5
- package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.mixin.ts +4 -0
- package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +2 -2
- package/src/shared/content-settings/components/payment-config-field/i18n/payment-config.pt-PT.json +16 -16
- package/src/shared/content-settings/components/shape-field/i18n/shape-field.fr-FR.json +1 -1
- package/src/shared/content-settings/components/testimonial-items-field/i18n/testimonial-items-field.fr-FR.json +1 -1
- package/src/shared/content-settings/components/text-field/TextField.vue +1 -1
- package/src/shared/content-settings/components/text-image-field/i18n/text-image-field.fr-FR.json +1 -1
- package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +2 -2
- package/src/shared/content-settings/components/textarea-field/TextareaField.vue +3 -3
- package/src/shared/content-settings/components/url-field/UrlField.mixin.ts +15 -10
- package/src/shared/content-settings/components/url-field/UrlField.vue +1 -0
- package/src/shared/ecommerce-settings/components/product-config-field/i18n/product-config-option.fr-FR.json +1 -1
- package/src/shared/my-uploads/i18n/my-uploads.de-DE.json +7 -7
- package/src/shared/my-uploads/i18n/my-uploads.es-ES.json +7 -7
- package/src/shared/my-uploads/i18n/my-uploads.fr-FR.json +7 -7
- package/src/shared/my-uploads/i18n/my-uploads.pt-PT.json +7 -7
- package/src/shared/publish-brand-page-with-state/i18n/publish-brand-page-modal-with-state.de-DE.json +5 -5
- package/src/shared/publish-brand-page-with-state/i18n/publish-brand-page-modal-with-state.es-ES.json +5 -5
- package/src/shared/publish-brand-page-with-state/i18n/publish-brand-page-modal-with-state.fr-FR.json +5 -5
- package/src/shared/publish-brand-page-with-state/i18n/publish-brand-page-modal-with-state.pt-PT.json +5 -5
- package/src/shared/style-settings/components/i18n/style-settings.de-DE.json +19 -19
- package/src/shared/style-settings/components/i18n/style-settings.es-ES.json +19 -19
- package/src/shared/style-settings/components/i18n/style-settings.fr-FR.json +19 -19
- package/src/shared/style-settings/components/i18n/style-settings.pt-PT.json +19 -19
- package/src/shared/template-settings/components/i18n/template-settings.es-ES.json +1 -1
- package/lib/src/bundled-translations.de-DE-CraYoDWg.js +0 -117
- package/lib/src/bundled-translations.es-ES-BYFsV_3B.js +0 -117
- package/lib/src/bundled-translations.fr-FR-DeAgOmt6.js +0 -117
- package/lib/src/bundled-translations.pt-PT-DUwBYmvH.js +0 -117
|
@@ -72,5 +72,6 @@ export interface BrandPageContext {
|
|
|
72
72
|
abTests?: AbTest;
|
|
73
73
|
/** Is brand page rendered for preview */
|
|
74
74
|
isCapturingPreview: boolean;
|
|
75
|
+
disableLogoRenderOnServerside?: boolean;
|
|
75
76
|
}
|
|
76
77
|
export declare const getAbTestResults: (abtestKeyValues: Record<string, string>) => AbTest;
|
|
@@ -207,6 +207,11 @@ export declare const BUTTON_LINK_TYPE: {
|
|
|
207
207
|
readonly tel: "tel";
|
|
208
208
|
};
|
|
209
209
|
export type ButtonLinkType = keyof typeof BUTTON_LINK_TYPE;
|
|
210
|
+
export declare const HYPERLINK_TYPE: {
|
|
211
|
+
readonly url: "url";
|
|
212
|
+
readonly page: "page";
|
|
213
|
+
};
|
|
214
|
+
export type HyperlinkType = keyof typeof HYPERLINK_TYPE;
|
|
210
215
|
export declare const URL_TYPE: {
|
|
211
216
|
readonly url: "url";
|
|
212
217
|
readonly email: "email";
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import type { BrandPageModel, LogoTheme, FabricLogoTheme, ButtonStyles, PageModel } from '../models';
|
|
1
|
+
import type { BrandPageModel, LogoTheme, ThemeColor, FabricLogoTheme, ButtonStyles, PageModel } from '../models';
|
|
2
2
|
import { NavigationDesktop, NavigationMobile } from '../models';
|
|
3
3
|
import { PageStyles, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop } from '../models';
|
|
4
|
+
/**
|
|
5
|
+
* @function getColorValueForCorrectCssProperty
|
|
6
|
+
* @param k: string
|
|
7
|
+
* @param colorData { rgb: 'rgb(0,255,0)', gradient: 'linear-gradient(180deg, rgb(0,0,0), rgb(255,0,0), 100%)'}
|
|
8
|
+
* @returns string - rgb() or linear-gradient()
|
|
9
|
+
*/
|
|
10
|
+
export declare const getColorValueForCorrectCssProperty: (k: string, colorData: ThemeColor) => string;
|
|
4
11
|
export declare const colorMatchCssKeyValue: (cssKey: string, cssValue: string, logoTheme: LogoTheme, applyColorWithMatchingLuminance?: {
|
|
5
12
|
originalColor: string;
|
|
6
13
|
}) => {
|
|
@@ -4,6 +4,7 @@ import { STYLE_THEME_KEYS } from '../constants';
|
|
|
4
4
|
import { arrayToLinearGradient, linearGradientToArray, isColorLinearGradient, RGBAtoHex, } from '../../utils/helpers';
|
|
5
5
|
import { addTransparentAlphaChannelToHex, calculateLuminanceRatio, getNewColorBasedOnTargetColorTheme, } from './color.util';
|
|
6
6
|
import chroma from 'chroma-js';
|
|
7
|
+
import { hasRTEContent } from '../../brand-page-maker/utils';
|
|
7
8
|
const MIN_LUM_RATIO = 0.3;
|
|
8
9
|
const parseFabricColorToCssStyle = (fabricColor) => {
|
|
9
10
|
if (fabricColor && typeof fabricColor === 'object') {
|
|
@@ -25,7 +26,7 @@ const parseFabricColorToCssStyle = (fabricColor) => {
|
|
|
25
26
|
* @param colorData { rgb: 'rgb(0,255,0)', gradient: 'linear-gradient(180deg, rgb(0,0,0), rgb(255,0,0), 100%)'}
|
|
26
27
|
* @returns string - rgb() or linear-gradient()
|
|
27
28
|
*/
|
|
28
|
-
const getColorValueForCorrectCssProperty = (k, colorData) => {
|
|
29
|
+
export const getColorValueForCorrectCssProperty = (k, colorData) => {
|
|
29
30
|
const gradientSupportedCssProperties = ['background', 'backgroundImage'];
|
|
30
31
|
return colorData.gradient && gradientSupportedCssProperties.indexOf(k) > -1
|
|
31
32
|
? colorData.gradient
|
|
@@ -49,13 +50,15 @@ export const colorMatchCssKeyValue = (cssKey, cssValue, logoTheme, applyColorWit
|
|
|
49
50
|
return { cssValue: newColor, isModified: true };
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
if (cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoTextColor, 'g')) ||
|
|
53
|
-
cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoTextMultiColor, 'g')))
|
|
53
|
+
if ((cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoTextColor, 'g')) ||
|
|
54
|
+
cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoTextMultiColor, 'g'))) &&
|
|
55
|
+
!hasRTEContent(cssValue)) {
|
|
54
56
|
cssValue = getColorValueForCorrectCssProperty(cssKey, logoTheme.logoTextColor);
|
|
55
57
|
return { cssValue, isModified: true };
|
|
56
58
|
}
|
|
57
|
-
else if (cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoBackgroundColor, 'g')) ||
|
|
58
|
-
cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoBackgroundMultiColor, 'g')))
|
|
59
|
+
else if ((cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoBackgroundColor, 'g')) ||
|
|
60
|
+
cssValue.match(new RegExp(STYLE_THEME_KEYS.LogoBackgroundMultiColor, 'g'))) &&
|
|
61
|
+
!hasRTEContent(cssValue)) {
|
|
59
62
|
cssValue = getColorValueForCorrectCssProperty(cssKey, logoTheme.logoBackgroundColor);
|
|
60
63
|
return { cssValue, isModified: true };
|
|
61
64
|
}
|
|
@@ -196,6 +199,8 @@ const CONTENT_STYLE_PROP_NAME_SUFFIX = [
|
|
|
196
199
|
'Color',
|
|
197
200
|
'Replacements',
|
|
198
201
|
];
|
|
202
|
+
const RTE_ALLOWED_SECTION_TYPES = ['text', 'banner-section'];
|
|
203
|
+
const RTE_ALLOWED_FIELDS = ['title', 'description', 'text', 'textItems'];
|
|
199
204
|
export const applyLogoThemeToContents = (logoTheme, pages) => {
|
|
200
205
|
let isModified = false;
|
|
201
206
|
const newPages = pages.map((page) => {
|
|
@@ -211,12 +216,60 @@ export const applyLogoThemeToContents = (logoTheme, pages) => {
|
|
|
211
216
|
newContent[styleKey] = newStyle;
|
|
212
217
|
isModified = isModified || isApplied;
|
|
213
218
|
}
|
|
219
|
+
const rteContentKeys = RTE_ALLOWED_SECTION_TYPES.includes(content.type)
|
|
220
|
+
? Object.keys(content).filter((k) => RTE_ALLOWED_FIELDS.includes(k))
|
|
221
|
+
: [];
|
|
222
|
+
for (const key of rteContentKeys) {
|
|
223
|
+
const { newRTEContent, isApplied } = applyLogoThemeToBrandPageRTEContentColorsRecursive(newContent[key], logoTheme, isModified);
|
|
224
|
+
newContent[key] = newRTEContent;
|
|
225
|
+
isModified = isModified || isApplied;
|
|
226
|
+
}
|
|
214
227
|
return newContent;
|
|
215
228
|
});
|
|
216
229
|
return { ...page, contents: newContents };
|
|
217
230
|
});
|
|
218
231
|
return { pages: newPages, isModified };
|
|
219
232
|
};
|
|
233
|
+
const applyLogoThemeToBrandPageRTEContentColorsRecursive = (content, logoTheme, isModified) => {
|
|
234
|
+
let isApplied = false;
|
|
235
|
+
let newRTEContent = {};
|
|
236
|
+
if (typeof content === 'string' && hasRTEContent(content)) {
|
|
237
|
+
newRTEContent = replaceRTEContentColors(content, logoTheme);
|
|
238
|
+
isApplied = true;
|
|
239
|
+
}
|
|
240
|
+
else if (Array.isArray(content)) {
|
|
241
|
+
newRTEContent = content.map((item) => {
|
|
242
|
+
const { newRTEContent: recursiveContent, isApplied: recursiveIsApplied } = applyLogoThemeToBrandPageRTEContentColorsRecursive(item, logoTheme, isModified);
|
|
243
|
+
isApplied = recursiveIsApplied;
|
|
244
|
+
return recursiveContent;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else if (typeof content === 'object') {
|
|
248
|
+
for (const [key, value] of Object.entries(content)) {
|
|
249
|
+
if (RTE_ALLOWED_FIELDS.includes(key) &&
|
|
250
|
+
typeof value === 'string' &&
|
|
251
|
+
hasRTEContent(value)) {
|
|
252
|
+
newRTEContent[key] = replaceRTEContentColors(value, logoTheme);
|
|
253
|
+
isApplied = true;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
newRTEContent[key] = value;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
newRTEContent = content;
|
|
262
|
+
isApplied = false;
|
|
263
|
+
}
|
|
264
|
+
return { isApplied, newRTEContent };
|
|
265
|
+
};
|
|
266
|
+
const replaceRTEContentColors = (content, logoTheme) => {
|
|
267
|
+
return content
|
|
268
|
+
.replace(new RegExp(`var\\(--${STYLE_THEME_KEYS.LogoTextColor}\\)`, 'g'), logoTheme.logoTextColor.rgb)
|
|
269
|
+
.replace(new RegExp(`var\\(--${STYLE_THEME_KEYS.LogoBackgroundColor}\\)`, 'g'), logoTheme.logoBackgroundColor.rgb)
|
|
270
|
+
.replace(new RegExp(`var\\(--${STYLE_THEME_KEYS.LogoTextMultiColor}\\)`, 'g'), logoTheme.logoTextColor.rgb)
|
|
271
|
+
.replace(new RegExp(`var\\(--${STYLE_THEME_KEYS.LogoBackgroundMultiColor}\\)`, 'g'), logoTheme.logoBackgroundColor.rgb);
|
|
272
|
+
};
|
|
220
273
|
export const applyLogoThemeToBrandPageStyles = (logoTheme, pageStyles) => {
|
|
221
274
|
let isModified = false;
|
|
222
275
|
const newStyle = new PageStyles();
|
package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/page-content-items.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const brandPageContentsSampleData: (import("../../../../brand-page").ButtonContent | import("../../../../brand-page").ProfileContent | import("../../../../brand-page").LogoContent)[];
|
|
1
|
+
export declare const brandPageContentsSampleData: (import("../../../../brand-page").ButtonContent | import("../../../../brand-page").ProfileContent | import("../../../../brand-page").TextContent | import("../../../../brand-page").LogoContent)[];
|
|
2
2
|
export declare const brandPageContentsSampleDataStarterKit: (import("../../../../brand-page").ButtonContent | import("../../../../brand-page").ProfileContent | import("../../../../brand-page").LogoContent)[];
|
package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/page-content-items.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { logoContent, profileContent, generalLink, facebookLink, websiteLink, emailLink, phoneLink, twitterLink, instagramLink, youtubeLink, linkedinLink, pinterestLink, twitchLink, tiktokLink, } from './content-settings-items.fixture';
|
|
1
|
+
import { logoContent, profileContent, generalLink, facebookLink, websiteLink, emailLink, phoneLink, twitterLink, instagramLink, youtubeLink, linkedinLink, pinterestLink, twitchLink, tiktokLink, textContent, } from './content-settings-items.fixture';
|
|
2
2
|
export const brandPageContentsSampleData = [
|
|
3
3
|
logoContent,
|
|
4
4
|
profileContent,
|
|
5
|
+
textContent,
|
|
5
6
|
generalLink,
|
|
6
7
|
websiteLink,
|
|
7
8
|
emailLink,
|
package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts
CHANGED
|
@@ -37,6 +37,38 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
37
37
|
selectedTemplateId: import("vue").ComputedRef<string | false>;
|
|
38
38
|
canUseRichTextEditor: import("vue").ComputedRef<boolean>;
|
|
39
39
|
isAdmin: import("vue").ComputedRef<boolean>;
|
|
40
|
+
logoTheme: import("vue").ComputedRef<{
|
|
41
|
+
logoTextColor: {
|
|
42
|
+
rgb: string;
|
|
43
|
+
gradient?: string | undefined;
|
|
44
|
+
50?: string | undefined;
|
|
45
|
+
100?: string | undefined;
|
|
46
|
+
200?: string | undefined;
|
|
47
|
+
300?: string | undefined;
|
|
48
|
+
400?: string | undefined;
|
|
49
|
+
500?: string | undefined;
|
|
50
|
+
600?: string | undefined;
|
|
51
|
+
700?: string | undefined;
|
|
52
|
+
800?: string | undefined;
|
|
53
|
+
900?: string | undefined;
|
|
54
|
+
950?: string | undefined;
|
|
55
|
+
};
|
|
56
|
+
logoBackgroundColor: {
|
|
57
|
+
rgb: string;
|
|
58
|
+
gradient?: string | undefined;
|
|
59
|
+
50?: string | undefined;
|
|
60
|
+
100?: string | undefined;
|
|
61
|
+
200?: string | undefined;
|
|
62
|
+
300?: string | undefined;
|
|
63
|
+
400?: string | undefined;
|
|
64
|
+
500?: string | undefined;
|
|
65
|
+
600?: string | undefined;
|
|
66
|
+
700?: string | undefined;
|
|
67
|
+
800?: string | undefined;
|
|
68
|
+
900?: string | undefined;
|
|
69
|
+
950?: string | undefined;
|
|
70
|
+
};
|
|
71
|
+
}>;
|
|
40
72
|
contentSettingsStore: import("pinia").Store<"uiContentSettings", import("../../../shared/content-settings/store").ContentSettingsState, {
|
|
41
73
|
contentErrorCount(): number;
|
|
42
74
|
getContent(state: {
|
|
@@ -1030,6 +1062,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
1030
1062
|
};
|
|
1031
1063
|
isDraggableEnabled(): boolean;
|
|
1032
1064
|
isItemSelected(): (itemIdx: any) => boolean;
|
|
1065
|
+
styleHtml(): string;
|
|
1033
1066
|
}, {
|
|
1034
1067
|
dispatchViewPortChangeEvent(): void;
|
|
1035
1068
|
onDraggingStart(): void;
|
package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js
CHANGED
|
@@ -14,6 +14,7 @@ import debounce from 'lodash.debounce';
|
|
|
14
14
|
import { transformToRTE } from '../../../brand-page-maker/utils';
|
|
15
15
|
import { useExternalRichTextEditor } from '../../../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
|
|
16
16
|
import { useUiStyleSettingsStore } from '../../../shared/style-settings/store';
|
|
17
|
+
import { STYLE_THEME_KEYS } from '../../../brand-page/constants';
|
|
17
18
|
export default defineComponent({
|
|
18
19
|
mixins: [PageMixin],
|
|
19
20
|
setup() {
|
|
@@ -40,6 +41,7 @@ export default defineComponent({
|
|
|
40
41
|
selectedTemplateId: computed(() => brandPageMakerStore.selectedTemplateId),
|
|
41
42
|
canUseRichTextEditor: computed(() => brandPageMakerUserStore.features.canUseRichTextEditor),
|
|
42
43
|
isAdmin: computed(() => brandPageMakerUserStore.isAdmin),
|
|
44
|
+
logoTheme: computed(() => uiStore.logoTheme),
|
|
43
45
|
contentSettingsStore,
|
|
44
46
|
brandPageMakerStore,
|
|
45
47
|
brandPageContainerStore,
|
|
@@ -97,6 +99,31 @@ export default defineComponent({
|
|
|
97
99
|
return this.isContentSelected ? item.id === this.selectedItemId : false;
|
|
98
100
|
};
|
|
99
101
|
},
|
|
102
|
+
styleHtml() {
|
|
103
|
+
if (!this.logoTheme) {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
// Generate CSS variables for logo theme colors
|
|
107
|
+
const cssVariables = Object.entries(STYLE_THEME_KEYS)
|
|
108
|
+
.map(([key, value]) => {
|
|
109
|
+
const themeColor = key.includes('Background')
|
|
110
|
+
? this.logoTheme.logoBackgroundColor
|
|
111
|
+
: this.logoTheme.logoTextColor;
|
|
112
|
+
if (themeColor?.rgb) {
|
|
113
|
+
return `--${value}: ${themeColor.rgb};`;
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
116
|
+
})
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.join('\n ');
|
|
119
|
+
return cssVariables
|
|
120
|
+
? `<style>
|
|
121
|
+
:root {
|
|
122
|
+
${cssVariables}
|
|
123
|
+
}
|
|
124
|
+
</style>`
|
|
125
|
+
: '';
|
|
126
|
+
},
|
|
100
127
|
},
|
|
101
128
|
mounted() {
|
|
102
129
|
this.dispatchViewPortChangeEvent();
|
|
@@ -180,7 +207,14 @@ export default defineComponent({
|
|
|
180
207
|
this.isContentSelected = true;
|
|
181
208
|
if ((item.type === 'banner-section' || item.type === 'text') &&
|
|
182
209
|
this.canUseRichTextEditor) {
|
|
183
|
-
|
|
210
|
+
let selectedItem = item;
|
|
211
|
+
if (this.isAdmin) {
|
|
212
|
+
const currentItem = this.items.find((i) => i.id === item.id);
|
|
213
|
+
if (currentItem) {
|
|
214
|
+
selectedItem = currentItem.settings.content;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
transformToRTE(this.pageSettingsStore, this.externalEditor, this.styleSettingsStore, selectedItem);
|
|
184
218
|
}
|
|
185
219
|
if (this.selectEventDebounceHandler) {
|
|
186
220
|
this.selectEventDebounceHandler();
|
|
@@ -185,6 +185,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
185
185
|
scaledContainerStyle(): BrandPageCssStyle;
|
|
186
186
|
innerContainerStyle(): BrandPageCssStyle;
|
|
187
187
|
isPersonalisable(): boolean;
|
|
188
|
+
cssVariablesStyle(): Record<string, string>;
|
|
188
189
|
}, {
|
|
189
190
|
onOverlayClicked(): void;
|
|
190
191
|
onResize(): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computed, defineComponent } from 'vue';
|
|
2
2
|
import { BRAND_PAGE_TYPES, MEDIA_SIZES, VIEWPORTS } from '../../../brand-page';
|
|
3
3
|
import { applyLogoThemeToBrandPageModel, applyUserPersonalisationToBrandPageModelAsync, getBrandPageViewModelFromBrandPageModel, } from '../../../brand-page/utils';
|
|
4
|
+
import { STYLE_THEME_KEYS } from '../../../brand-page/constants';
|
|
4
5
|
import debounce from 'lodash.debounce';
|
|
5
6
|
import { MOBILE_HEIGHT, MOBILE_WIDTH } from '../../constants';
|
|
6
7
|
import { useBrandPageMakerStore } from '../../stores';
|
|
@@ -128,6 +129,22 @@ export default defineComponent({
|
|
|
128
129
|
isPersonalisable() {
|
|
129
130
|
return this.template.isPersonalisable || false;
|
|
130
131
|
},
|
|
132
|
+
cssVariablesStyle() {
|
|
133
|
+
if (!this.logoTheme) {
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
136
|
+
const cssVariables = {};
|
|
137
|
+
// Generate CSS variables for logo theme colors
|
|
138
|
+
Object.entries(STYLE_THEME_KEYS).forEach(([key, value]) => {
|
|
139
|
+
const themeColor = key.includes('Background')
|
|
140
|
+
? this.logoTheme.logoBackgroundColor
|
|
141
|
+
: this.logoTheme.logoTextColor;
|
|
142
|
+
if (themeColor?.rgb) {
|
|
143
|
+
cssVariables[`--${value}`] = themeColor.rgb;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return cssVariables;
|
|
147
|
+
},
|
|
131
148
|
},
|
|
132
149
|
watch: {
|
|
133
150
|
logoTheme: {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Editor } from '@tiptap/vue-3';
|
|
2
|
+
import type { Ref } from 'vue';
|
|
3
|
+
export declare const useBubbleMenu: (editor: Editor, isHyperlinkPopupOpen?: Ref<boolean>) => {
|
|
4
|
+
shouldShow: ({ editor, state }: {
|
|
5
|
+
editor: any;
|
|
6
|
+
state: any;
|
|
7
|
+
}) => any;
|
|
8
|
+
tippyOptions: {
|
|
9
|
+
duration: number;
|
|
10
|
+
placement: "bottom";
|
|
11
|
+
interactive: boolean;
|
|
12
|
+
appendTo: "parent";
|
|
13
|
+
hideOnClick: boolean;
|
|
14
|
+
arrow: boolean;
|
|
15
|
+
offset: [number, number];
|
|
16
|
+
trigger: "manual";
|
|
17
|
+
zIndex: number;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const useBubbleMenu = (editor, isHyperlinkPopupOpen) => {
|
|
2
|
+
const shouldShow = ({ editor, state }) => {
|
|
3
|
+
if (!editor || !state)
|
|
4
|
+
return false;
|
|
5
|
+
// Hide preview popup if the hyperlink popup is open
|
|
6
|
+
if (isHyperlinkPopupOpen?.value)
|
|
7
|
+
return false;
|
|
8
|
+
const { selection } = state;
|
|
9
|
+
// Only show bubble menu if there's a selection and it contains a link
|
|
10
|
+
if (!selection.empty) {
|
|
11
|
+
const linkAttrs = editor.getAttributes('link');
|
|
12
|
+
return linkAttrs.href && linkAttrs.href.trim() !== '';
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
const tippyOptions = {
|
|
17
|
+
duration: 100,
|
|
18
|
+
placement: 'bottom',
|
|
19
|
+
interactive: true,
|
|
20
|
+
appendTo: 'parent',
|
|
21
|
+
hideOnClick: false,
|
|
22
|
+
arrow: false,
|
|
23
|
+
offset: [0, 10],
|
|
24
|
+
trigger: 'manual',
|
|
25
|
+
zIndex: 10,
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
shouldShow,
|
|
29
|
+
tippyOptions,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
3
|
+
const LINK_COLOR = '#0097d7';
|
|
4
|
+
const isLinkMark = (mark) => mark.type.name === 'link';
|
|
5
|
+
const isUnderlineMark = (mark) => mark.type.name === 'underline';
|
|
6
|
+
const isTextStyleMark = (mark) => mark.type.name === 'textStyle';
|
|
7
|
+
const isBlueColorMark = (mark) => isTextStyleMark(mark) && mark.attrs.color === LINK_COLOR;
|
|
8
|
+
const hasLinkMark = (marks) => marks.some(isLinkMark);
|
|
9
|
+
const hasUnderlineMark = (marks) => marks.some(isUnderlineMark);
|
|
10
|
+
const createStylesWithoutColor = (schema, textStyleMark) => {
|
|
11
|
+
const { color: _color, ...otherAttrs } = textStyleMark.attrs;
|
|
12
|
+
return Object.keys(otherAttrs).length > 0
|
|
13
|
+
? schema.marks.textStyle?.create(otherAttrs)
|
|
14
|
+
: null;
|
|
15
|
+
};
|
|
16
|
+
const applyDefaultLinkStyling = (tr, schema, node, pos) => {
|
|
17
|
+
const range = { from: pos, to: pos + node.nodeSize };
|
|
18
|
+
let modified = false;
|
|
19
|
+
const textStyleMark = node.marks.find(isTextStyleMark);
|
|
20
|
+
// Always apply blue color to newly created links, regardless of existing colors
|
|
21
|
+
const attrs = { ...textStyleMark?.attrs, color: LINK_COLOR };
|
|
22
|
+
const colorMark = schema.marks.textStyle?.create(attrs);
|
|
23
|
+
if (colorMark) {
|
|
24
|
+
if (textStyleMark) {
|
|
25
|
+
tr.removeMark(range.from, range.to, textStyleMark);
|
|
26
|
+
}
|
|
27
|
+
tr.addMark(range.from, range.to, colorMark);
|
|
28
|
+
modified = true;
|
|
29
|
+
}
|
|
30
|
+
// Add underline to newly detected URLs (auto-links)
|
|
31
|
+
// This ensures typed URLs get the same styling as manually created links
|
|
32
|
+
if (!hasUnderlineMark(node.marks)) {
|
|
33
|
+
const underlineMark = schema.marks.underline?.create();
|
|
34
|
+
if (underlineMark) {
|
|
35
|
+
tr.addMark(range.from, range.to, underlineMark);
|
|
36
|
+
modified = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return modified;
|
|
40
|
+
};
|
|
41
|
+
const removeHyperlinkStyles = (tr, schema, node, pos) => {
|
|
42
|
+
const range = { from: pos, to: pos + node.nodeSize };
|
|
43
|
+
let modified = false;
|
|
44
|
+
// Only remove blue color that was added for link styling
|
|
45
|
+
const textStyleMark = node.marks.find(isBlueColorMark);
|
|
46
|
+
if (textStyleMark) {
|
|
47
|
+
tr.removeMark(range.from, range.to, textStyleMark);
|
|
48
|
+
const newTextStyleMark = createStylesWithoutColor(schema, textStyleMark);
|
|
49
|
+
if (newTextStyleMark) {
|
|
50
|
+
tr.addMark(range.from, range.to, newTextStyleMark);
|
|
51
|
+
}
|
|
52
|
+
modified = true;
|
|
53
|
+
}
|
|
54
|
+
// Don't automatically remove underlines from non-link text
|
|
55
|
+
// Users should be able to have underlined text that's not a link
|
|
56
|
+
return modified;
|
|
57
|
+
};
|
|
58
|
+
export const AutoLink = Extension.create({
|
|
59
|
+
name: 'autoLink',
|
|
60
|
+
addKeyboardShortcuts() {
|
|
61
|
+
return {
|
|
62
|
+
// Handle any character input at the end of links
|
|
63
|
+
Backspace: () => false, // Let default behavior handle backspace
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
addProseMirrorPlugins() {
|
|
67
|
+
return [
|
|
68
|
+
new Plugin({
|
|
69
|
+
key: new PluginKey('autoLinkStyling'),
|
|
70
|
+
props: {
|
|
71
|
+
handleTextInput(view, from, to, text) {
|
|
72
|
+
const { state } = view;
|
|
73
|
+
const { selection } = state;
|
|
74
|
+
const { $anchor } = selection;
|
|
75
|
+
// Only handle when typing at a cursor position (from === to)
|
|
76
|
+
if (from !== to) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
// Check if we have link marks at cursor position
|
|
80
|
+
const currentMarks = $anchor.marks();
|
|
81
|
+
const linkMark = currentMarks.find(isLinkMark);
|
|
82
|
+
if (linkMark) {
|
|
83
|
+
// Check if we're at the end of the link
|
|
84
|
+
const currentPos = $anchor.pos;
|
|
85
|
+
const nextPos = currentPos + 1;
|
|
86
|
+
const hasLinkAfter = nextPos <= state.doc.content.size &&
|
|
87
|
+
state.doc
|
|
88
|
+
.resolve(Math.min(nextPos, state.doc.content.size))
|
|
89
|
+
.marks()
|
|
90
|
+
.some((mark) => isLinkMark(mark) && mark.eq(linkMark));
|
|
91
|
+
if (!hasLinkAfter) {
|
|
92
|
+
// detach the link after the attached link mark
|
|
93
|
+
const preservedMarks = currentMarks
|
|
94
|
+
.filter((mark) => {
|
|
95
|
+
if (isLinkMark(mark))
|
|
96
|
+
return false;
|
|
97
|
+
// Only preserve underlines if there's no blue color (manually added underlines)
|
|
98
|
+
// Remove underlines that were part of link styling (with blue color)
|
|
99
|
+
if (isUnderlineMark(mark)) {
|
|
100
|
+
const hasBlueColor = currentMarks.some(isBlueColorMark);
|
|
101
|
+
return !hasBlueColor; // Keep underline only if no blue color
|
|
102
|
+
}
|
|
103
|
+
// Remove blue color styling but preserve other text styles
|
|
104
|
+
if (isBlueColorMark(mark)) {
|
|
105
|
+
return createStylesWithoutColor(state.schema, mark);
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
})
|
|
109
|
+
.filter(Boolean); // Insert text with only preserved marks
|
|
110
|
+
let tr = state.tr;
|
|
111
|
+
tr = tr.setStoredMarks(preservedMarks);
|
|
112
|
+
tr = tr.insertText(text, from, to);
|
|
113
|
+
tr = tr.setMeta('autoLinkDetached', true);
|
|
114
|
+
view.dispatch(tr);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
appendTransaction(transactions, oldState, newState) {
|
|
122
|
+
const tr = newState.tr;
|
|
123
|
+
let modified = false;
|
|
124
|
+
const hasDocChanges = transactions.some((transaction) => transaction.docChanged);
|
|
125
|
+
if (!hasDocChanges)
|
|
126
|
+
return null;
|
|
127
|
+
const wasDetached = transactions.some((transaction) => transaction.getMeta('autoLinkDetached'));
|
|
128
|
+
// Apply default styling to links (unless just detached)
|
|
129
|
+
if (!wasDetached) {
|
|
130
|
+
newState.doc.descendants((node, pos) => {
|
|
131
|
+
if (!node.isText || !node.text || !hasLinkMark(node.marks))
|
|
132
|
+
return;
|
|
133
|
+
// Check if this is a newly created link by comparing with old state
|
|
134
|
+
const oldNode = pos < oldState.doc.nodeSize ? oldState.doc.nodeAt(pos) : null;
|
|
135
|
+
const wasAlreadyLink = oldNode && hasLinkMark(oldNode.marks);
|
|
136
|
+
// Only apply full styling (including underline) to newly created links
|
|
137
|
+
if (wasAlreadyLink === false) {
|
|
138
|
+
if (applyDefaultLinkStyling(tr, newState.schema, node, pos)) {
|
|
139
|
+
modified = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// For existing links, preserve their current color and underline choices
|
|
144
|
+
// Don't override user customizations on existing links
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// Clean up hyperlink styling from text without link marks
|
|
149
|
+
newState.doc.descendants((node, pos) => {
|
|
150
|
+
if (!node.isText || !node.text || hasLinkMark(node.marks))
|
|
151
|
+
return;
|
|
152
|
+
if (removeHyperlinkStyles(tr, newState.schema, node, pos)) {
|
|
153
|
+
modified = true;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return modified ? tr : null;
|
|
157
|
+
},
|
|
158
|
+
}),
|
|
159
|
+
];
|
|
160
|
+
},
|
|
161
|
+
});
|
|
@@ -42,7 +42,7 @@ export const MaxLength = Extension.create({
|
|
|
42
42
|
const text = node.text ?? '';
|
|
43
43
|
const piece = text.slice(0, remaining);
|
|
44
44
|
if (piece.length > 0) {
|
|
45
|
-
nodes.push(node.type.
|
|
45
|
+
nodes.push(node.type.schema.text(piece, node.marks));
|
|
46
46
|
remaining -= piece.length;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -64,7 +64,7 @@ export const MaxLength = Extension.create({
|
|
|
64
64
|
const piece = (subNode.text ?? '').slice(0, remaining);
|
|
65
65
|
if (piece.length === 0)
|
|
66
66
|
return null;
|
|
67
|
-
const newText = subNode.type.
|
|
67
|
+
const newText = subNode.type.schema.text(piece, subNode.marks);
|
|
68
68
|
remaining -= piece.length;
|
|
69
69
|
return newText;
|
|
70
70
|
}
|
|
@@ -77,7 +77,7 @@ export const MaxLength = Extension.create({
|
|
|
77
77
|
});
|
|
78
78
|
if (children.length === 0)
|
|
79
79
|
return null;
|
|
80
|
-
return subNode.
|
|
80
|
+
return subNode.copy(Fragment.fromArray(children));
|
|
81
81
|
}
|
|
82
82
|
return null;
|
|
83
83
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Editor } from '@tiptap/vue-3';
|
|
2
|
+
export declare const useHyperlink: (editor: Editor) => {
|
|
3
|
+
hyperlinkValue: import("vue").WritableComputedRef<{
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}, {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
value: string;
|
|
11
|
+
}>;
|
|
12
|
+
setHyperlinkUrl: (url: string) => void;
|
|
13
|
+
setHyperlinkUrlValue: (url: string) => void;
|
|
14
|
+
removeHyperlink: (clearUrlValue?: boolean) => void;
|
|
15
|
+
applyHyperlinkToEditor: (url: string, text?: string, selection?: {
|
|
16
|
+
from: number;
|
|
17
|
+
to: number;
|
|
18
|
+
}) => void;
|
|
19
|
+
};
|