@vonage/vivid 5.20.1 → 5.22.0
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/accordion/index.cjs +1 -1
- package/accordion/index.js +2 -2
- package/alert/index.cjs +1 -1
- package/alert/index.js +2 -2
- package/audio-player/index.cjs +3 -5
- package/audio-player/index.js +30 -32
- package/avatar/index.cjs +1 -1
- package/avatar/index.js +1 -1
- package/banner/index.cjs +1 -1
- package/banner/index.js +2 -2
- package/bundled/affix.cjs +4 -4
- package/bundled/affix.js +4 -4
- package/bundled/base-color-picker.cjs +2 -2
- package/bundled/base-color-picker.js +2 -2
- package/bundled/button.cjs +1 -1
- package/bundled/button.js +1 -1
- package/bundled/definition10.cjs +1 -1
- package/bundled/definition10.js +1 -1
- package/bundled/definition13.cjs +1 -1
- package/bundled/definition13.js +1 -1
- package/bundled/definition15.cjs +1 -1
- package/bundled/definition15.js +2 -2
- package/bundled/definition16.cjs +2 -2
- package/bundled/definition16.js +2 -2
- package/bundled/definition17.cjs +1 -1
- package/bundled/definition17.js +1 -1
- package/bundled/definition18.cjs +2 -2
- package/bundled/definition18.js +15 -6
- package/bundled/definition19.cjs +1 -1
- package/bundled/definition19.js +1 -1
- package/bundled/definition20.cjs +1 -1
- package/bundled/definition20.js +1 -1
- package/bundled/definition21.cjs +1 -1
- package/bundled/definition21.js +2 -2
- package/bundled/definition24.cjs +1 -1
- package/bundled/definition24.js +1 -1
- package/bundled/definition3.cjs +1 -1
- package/bundled/definition3.js +3 -3
- package/bundled/definition4.cjs +1 -1
- package/bundled/definition4.js +1 -1
- package/bundled/definition5.cjs +1 -1
- package/bundled/definition5.js +1 -1
- package/bundled/definition6.cjs +1 -1
- package/bundled/definition6.js +2 -2
- package/bundled/definition8.cjs +1 -1
- package/bundled/definition8.js +12 -6
- package/bundled/definition9.cjs +1 -1
- package/bundled/definition9.js +1 -1
- package/bundled/form-associated.cjs +1 -1
- package/bundled/form-associated.js +2 -2
- package/bundled/listbox.cjs +1 -1
- package/bundled/listbox.js +5 -5
- package/bundled/numberConverter.cjs +1 -1
- package/bundled/numberConverter.js +1 -1
- package/bundled/slider.template.cjs +1 -1
- package/bundled/slider.template.js +1 -1
- package/bundled/vivid-element.cjs +1 -1
- package/bundled/vivid-element.js +1 -1
- package/bundled/with-contextual-help.cjs +1 -1
- package/bundled/with-contextual-help.js +1 -1
- package/calendar/index.cjs +1 -1
- package/calendar/index.js +3 -3
- package/color-picker/index.cjs +20 -20
- package/color-picker/index.js +22 -22
- package/combobox/index.cjs +1 -1
- package/combobox/index.js +7 -7
- package/country-group/index.cjs +1 -1
- package/country-group/index.js +1 -1
- package/custom-elements.json +227 -185
- package/data-grid/index.cjs +2 -2
- package/data-grid/index.js +12 -10
- package/dial-pad/index.cjs +1 -1
- package/dial-pad/index.js +2 -2
- package/dialog/index.cjs +1 -1
- package/dialog/index.js +1 -1
- package/file-picker/index.cjs +1 -1
- package/file-picker/index.js +1 -1
- package/header/index.cjs +1 -1
- package/header/index.js +1 -1
- package/lib/audio-player/audio-player.d.ts +0 -1
- package/lib/calendar/helpers/calendar.keyboard-interactions.d.ts +1 -1
- package/lib/checkbox/checkbox.d.ts +16 -16
- package/lib/color-picker/color-picker.d.ts +16 -16
- package/lib/combobox/combobox.d.ts +21 -21
- package/lib/date-picker/date-picker.d.ts +26 -26
- package/lib/date-range-picker/date-range-picker.d.ts +14 -14
- package/lib/date-time-picker/date-time-picker.d.ts +24 -24
- package/lib/dial-pad/dial-pad.d.ts +1 -1
- package/lib/file-picker/file-picker.d.ts +21 -21
- package/lib/menu/menu.d.ts +1 -1
- package/lib/number-field/number-field.d.ts +22 -22
- package/lib/popup/popup.d.ts +2 -1
- package/lib/radio/radio.d.ts +16 -16
- package/lib/range-slider/range-slider.d.ts +10 -10
- package/lib/rich-text-editor/popover.d.ts +1 -1
- package/lib/rich-text-editor/rte/exports.d.ts +1 -0
- package/lib/rich-text-editor/rte/feature.d.ts +5 -5
- package/lib/rich-text-editor/rte/features/base.d.ts +1 -0
- package/lib/rich-text-editor/rte/features/drop-handler.d.ts +1 -2
- package/lib/rich-text-editor/rte/features/internal/core.d.ts +8 -0
- package/lib/rich-text-editor/rte/features/internal/history.d.ts +6 -0
- package/lib/rich-text-editor/rte/features/keyboard-shortcuts.d.ts +1 -1
- package/lib/rich-text-editor/rte/features/text-color-picker.d.ts +1 -1
- package/lib/rich-text-editor/rte/instance.d.ts +1 -0
- package/lib/rich-text-editor/rte/public-interface.d.ts +3 -0
- package/lib/rich-text-editor/rte/utils/ui.d.ts +1 -1
- package/lib/searchable-select/searchable-select.d.ts +21 -21
- package/lib/select/select.d.ts +22 -22
- package/lib/simple-color-picker/simple-color-picker.d.ts +5 -5
- package/lib/slider/slider.d.ts +5 -5
- package/lib/switch/switch.d.ts +5 -5
- package/lib/table/table-body.template.d.ts +1 -2
- package/lib/table/table-cell.template.d.ts +1 -2
- package/lib/table/table-head.template.d.ts +1 -2
- package/lib/table/table-row.template.d.ts +1 -2
- package/lib/table/table.template.d.ts +1 -2
- package/lib/text-area/text-area.d.ts +21 -21
- package/lib/text-field/text-field.d.ts +22 -22
- package/lib/time-picker/time-picker.d.ts +12 -12
- package/locales/de-DE.cjs +178 -4
- package/locales/de-DE.js +179 -2
- package/locales/en-GB.cjs +9 -4
- package/locales/en-GB.js +10 -2
- package/locales/en-US.cjs +2 -270
- package/locales/en-US.js +1 -267
- package/locales/ja-JP.cjs +171 -4
- package/locales/ja-JP.js +172 -2
- package/locales/zh-CN.cjs +172 -4
- package/locales/zh-CN.js +173 -2
- package/nav-disclosure/index.cjs +1 -1
- package/nav-disclosure/index.js +1 -1
- package/nav-item/index.cjs +1 -1
- package/nav-item/index.js +1 -1
- package/package.json +7 -4
- package/pagination/index.cjs +1 -1
- package/pagination/index.js +9 -2
- package/popover/index.cjs +1 -1
- package/popover/index.js +1 -1
- package/progress/index.cjs +1 -1
- package/progress/index.js +1 -1
- package/radio-group/index.cjs +1 -1
- package/radio-group/index.js +21 -19
- package/range-slider/index.cjs +1 -1
- package/range-slider/index.js +1 -1
- package/rich-text-editor/index.cjs +13 -12
- package/rich-text-editor/index.js +1085 -1057
- package/searchable-select/index.cjs +1 -1
- package/searchable-select/index.js +1 -1
- package/selectable-box/index.cjs +1 -1
- package/selectable-box/index.js +6 -1
- package/shared/color-picker/base-color-picker.d.ts +5 -5
- package/shared/feedback/mixins.d.ts +1 -1
- package/shared/foundation/button/button.d.ts +5 -5
- package/shared/foundation/form-associated/form-associated.d.ts +10 -10
- package/shared/foundation/listbox/listbox.d.ts +1 -1
- package/shared/patterns/form-elements/form-element.d.ts +5 -5
- package/shared/patterns/form-elements/with-contextual-help.d.ts +5 -5
- package/shared/patterns/form-elements/with-error-text.d.ts +6 -6
- package/shared/picker-field/mixins/calendar-picker.d.ts +6 -6
- package/shared/picker-field/mixins/calendar-picker.template.d.ts +6 -6
- package/shared/picker-field/mixins/min-max-calendar-picker.d.ts +8 -8
- package/shared/picker-field/mixins/single-date-picker.d.ts +6 -6
- package/shared/picker-field/mixins/single-value-picker.d.ts +6 -6
- package/shared/picker-field/mixins/time-selection-picker.d.ts +6 -6
- package/shared/picker-field/mixins/time-selection-picker.template.d.ts +12 -12
- package/shared/picker-field/picker-field.d.ts +21 -21
- package/shared/utils/slottable-request.d.ts +1 -1
- package/switch/index.cjs +2 -2
- package/switch/index.js +2 -2
- package/table/index.cjs +5 -5
- package/table/index.js +5 -5
- package/tabs/index.cjs +1 -1
- package/tabs/index.js +3 -3
- package/tag/index.cjs +1 -1
- package/tag/index.js +1 -1
- package/tree-view/index.cjs +1 -1
- package/tree-view/index.js +0 -2
- package/unbundled/affix.cjs +4 -4
- package/unbundled/affix.js +4 -4
- package/unbundled/base-color-picker.cjs +3 -3
- package/unbundled/base-color-picker.js +3 -3
- package/unbundled/button.cjs +5 -5
- package/unbundled/button.js +5 -5
- package/unbundled/chunk.cjs +15 -0
- package/unbundled/chunk.js +13 -0
- package/unbundled/definition10.cjs +15 -4
- package/unbundled/definition10.js +15 -4
- package/unbundled/definition11.cjs +3 -3
- package/unbundled/definition11.js +3 -3
- package/unbundled/definition12.cjs +1 -1
- package/unbundled/definition12.js +1 -1
- package/unbundled/definition13.cjs +2 -2
- package/unbundled/definition13.js +2 -2
- package/unbundled/definition14.cjs +73 -76
- package/unbundled/definition14.js +73 -76
- package/unbundled/definition15.cjs +1 -1
- package/unbundled/definition15.js +1 -1
- package/unbundled/definition17.cjs +2 -2
- package/unbundled/definition17.js +2 -2
- package/unbundled/definition19.cjs +2 -1
- package/unbundled/definition19.js +2 -1
- package/unbundled/definition2.cjs +1 -1
- package/unbundled/definition2.js +1 -1
- package/unbundled/definition21.cjs +3 -3
- package/unbundled/definition21.js +3 -3
- package/unbundled/definition23.cjs +2 -2
- package/unbundled/definition23.js +2 -2
- package/unbundled/definition24.cjs +1 -1
- package/unbundled/definition24.js +1 -1
- package/unbundled/definition27.cjs +1 -1
- package/unbundled/definition27.js +1 -1
- package/unbundled/definition28.cjs +23 -23
- package/unbundled/definition28.js +23 -23
- package/unbundled/definition29.cjs +1 -1
- package/unbundled/definition29.js +1 -1
- package/unbundled/definition3.cjs +2 -2
- package/unbundled/definition3.js +2 -2
- package/unbundled/definition30.cjs +8 -8
- package/unbundled/definition30.js +8 -8
- package/unbundled/definition32.cjs +1 -1
- package/unbundled/definition32.js +1 -1
- package/unbundled/definition34.cjs +9 -8
- package/unbundled/definition34.js +9 -8
- package/unbundled/definition35.cjs +1 -1
- package/unbundled/definition35.js +1 -1
- package/unbundled/definition39.cjs +2 -2
- package/unbundled/definition39.js +2 -2
- package/unbundled/definition40.cjs +1 -1
- package/unbundled/definition40.js +1 -1
- package/unbundled/definition43.cjs +1 -1
- package/unbundled/definition43.js +1 -1
- package/unbundled/definition44.cjs +1 -1
- package/unbundled/definition44.js +1 -1
- package/unbundled/definition48.cjs +1 -1
- package/unbundled/definition48.js +1 -1
- package/unbundled/definition49.cjs +1 -1
- package/unbundled/definition49.js +1 -1
- package/unbundled/definition5.cjs +1 -1
- package/unbundled/definition5.js +1 -1
- package/unbundled/definition53.cjs +10 -3
- package/unbundled/definition53.js +10 -3
- package/unbundled/definition55.cjs +1 -1
- package/unbundled/definition55.js +1 -1
- package/unbundled/definition56.cjs +1 -1
- package/unbundled/definition56.js +1 -1
- package/unbundled/definition57.cjs +4 -5
- package/unbundled/definition57.js +4 -5
- package/unbundled/definition58.cjs +20 -19
- package/unbundled/definition58.js +20 -19
- package/unbundled/definition59.cjs +1 -1
- package/unbundled/definition59.js +1 -1
- package/unbundled/definition60.cjs +890 -851
- package/unbundled/definition60.js +890 -851
- package/unbundled/definition61.cjs +13 -7
- package/unbundled/definition61.js +13 -7
- package/unbundled/definition63.cjs +1 -1
- package/unbundled/definition63.js +1 -1
- package/unbundled/definition64.cjs +4 -1
- package/unbundled/definition64.js +4 -1
- package/unbundled/definition65.cjs +2 -1
- package/unbundled/definition65.js +2 -1
- package/unbundled/definition69.cjs +4 -3
- package/unbundled/definition69.js +4 -3
- package/unbundled/definition7.cjs +2 -2
- package/unbundled/definition7.js +2 -2
- package/unbundled/definition71.cjs +1 -1
- package/unbundled/definition71.js +1 -1
- package/unbundled/definition72.cjs +5 -5
- package/unbundled/definition72.js +5 -5
- package/unbundled/definition73.cjs +3 -3
- package/unbundled/definition73.js +3 -3
- package/unbundled/definition75.cjs +1 -1
- package/unbundled/definition75.js +1 -1
- package/unbundled/definition78.cjs +1 -1
- package/unbundled/definition78.js +1 -1
- package/unbundled/definition79.cjs +0 -2
- package/unbundled/definition79.js +0 -2
- package/unbundled/definition80.cjs +1 -1
- package/unbundled/definition80.js +1 -1
- package/unbundled/definition9.cjs +2 -2
- package/unbundled/definition9.js +2 -2
- package/unbundled/en-US.cjs +449 -0
- package/unbundled/en-US.js +445 -0
- package/unbundled/form-associated.cjs +2 -2
- package/unbundled/form-associated.js +2 -2
- package/unbundled/listbox.cjs +7 -7
- package/unbundled/listbox.js +7 -7
- package/unbundled/localized.cjs +2 -2
- package/unbundled/localized.js +1 -1
- package/unbundled/numberConverter.cjs +1 -1
- package/unbundled/numberConverter.js +1 -1
- package/unbundled/slider.template.cjs +1 -1
- package/unbundled/slider.template.js +1 -1
- package/unbundled/slottable-request.cjs +5 -5
- package/unbundled/slottable-request.js +5 -5
- package/unbundled/vivid-element.cjs +1 -1
- package/unbundled/vivid-element.js +1 -1
- package/unbundled/with-contextual-help.cjs +4 -1
- package/unbundled/with-contextual-help.js +4 -1
- package/video-player/index.cjs +1 -1
- package/video-player/index.js +1 -1
- package/vivid.api.json +60 -18
|
@@ -23,9 +23,9 @@ let prosemirror_keymap = require("prosemirror-keymap");
|
|
|
23
23
|
let prosemirror_commands = require("prosemirror-commands");
|
|
24
24
|
let prosemirror_dropcursor = require("prosemirror-dropcursor");
|
|
25
25
|
let prosemirror_gapcursor = require("prosemirror-gapcursor");
|
|
26
|
-
let prosemirror_history = require("prosemirror-history");
|
|
27
26
|
let dompurify = require("dompurify");
|
|
28
27
|
dompurify = require_chunk.__toESM(dompurify, 1);
|
|
28
|
+
let prosemirror_history = require("prosemirror-history");
|
|
29
29
|
let prosemirror_inputrules = require("prosemirror-inputrules");
|
|
30
30
|
let prosemirror_transform = require("prosemirror-transform");
|
|
31
31
|
let prosemirror_schema_basic = require("prosemirror-schema-basic");
|
|
@@ -113,12 +113,20 @@ var Kind = {
|
|
|
113
113
|
default: {
|
|
114
114
|
placement: void 0,
|
|
115
115
|
placementStrategy: require_definition$2.PlacementStrategy.AutoPlacementHorizontal,
|
|
116
|
+
shiftCrossAxis: false,
|
|
116
117
|
strategy: "absolute"
|
|
117
118
|
},
|
|
118
119
|
autocomplete: {
|
|
119
120
|
placement: "bottom-start",
|
|
120
121
|
placementStrategy: require_definition$2.PlacementStrategy.Flip,
|
|
122
|
+
shiftCrossAxis: false,
|
|
121
123
|
strategy: "fixed"
|
|
124
|
+
},
|
|
125
|
+
imageOptions: {
|
|
126
|
+
placement: "bottom",
|
|
127
|
+
placementStrategy: require_definition$2.PlacementStrategy.Flip,
|
|
128
|
+
shiftCrossAxis: true,
|
|
129
|
+
strategy: "absolute"
|
|
122
130
|
}
|
|
123
131
|
};
|
|
124
132
|
var popoverTemplate = (context) => {
|
|
@@ -127,6 +135,7 @@ var popoverTemplate = (context) => {
|
|
|
127
135
|
:anchor="${(x) => x.anchorEl}"
|
|
128
136
|
:placement="${(x) => Kind[x.kind].placement}"
|
|
129
137
|
:placementStrategy="${(x) => Kind[x.kind].placementStrategy}"
|
|
138
|
+
:shiftCrossAxis="${(x) => Kind[x.kind].shiftCrossAxis}"
|
|
130
139
|
:open="${(x) => x.open}"
|
|
131
140
|
:offset="${(x) => x.offset}"
|
|
132
141
|
:strategy="${(x) => Kind[x.kind].strategy}"
|
|
@@ -240,927 +249,942 @@ var FeatureState = class {
|
|
|
240
249
|
//#region src/lib/rich-text-editor/rte/features/internal/core.style.scss?inline
|
|
241
250
|
var core_style_default = ".ProseMirror{box-sizing:border-box;padding:var(--editor-padding-block) var(--editor-padding-inline);outline:none;flex:1 0 0}.ProseMirror-selectednode{--focus-stroke-gap-color:transparent;--focus-border-radius:2px;outline:none;position:relative}.ProseMirror-selectednode:after{box-shadow:0 0 0 4px color-mix(in srgb, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px));border-radius:var(--focus-border-radius,inherit);block-size:calc(100% + var(--focus-block-size-addition,4px));content:\"\";inline-size:calc(100% + var(--focus-block-size-addition,4px));display:block;position:absolute;inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}.editor--disabled .ProseMirror{color:var(--vvd-color-neutral-300);cursor:not-allowed}";
|
|
242
251
|
//#endregion
|
|
243
|
-
//#region src/lib/rich-text-editor/rte/
|
|
244
|
-
var
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
handler
|
|
249
|
-
];
|
|
250
|
-
var UiCtx = class {
|
|
251
|
-
constructor(view, rte, props) {
|
|
252
|
-
this.view = view;
|
|
253
|
-
this.rte = rte;
|
|
254
|
-
this.props = props;
|
|
255
|
-
this.bindings = [];
|
|
252
|
+
//#region src/lib/rich-text-editor/rte/features/internal/foreign-html.ts
|
|
253
|
+
var RteForeignHtmlFeatureImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
254
|
+
constructor(..._args) {
|
|
255
|
+
super(..._args);
|
|
256
|
+
this.name = "RteForeignHtmlFeature";
|
|
256
257
|
}
|
|
257
|
-
|
|
258
|
-
return
|
|
258
|
+
getPlugins(rte) {
|
|
259
|
+
return [this.contribution(new prosemirror_state.Plugin({ props: {
|
|
260
|
+
transformPastedHTML: (html) => rte.foreignHtmlParser[require_slottable_request.impl].transform(html),
|
|
261
|
+
clipboardParser: rte.foreignHtmlParser[require_slottable_request.impl].parser,
|
|
262
|
+
clipboardSerializer: rte.foreignHtmlSerializer[require_slottable_request.impl].serializer
|
|
263
|
+
} }))];
|
|
259
264
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/lib/rich-text-editor/rte/features/internal/cursor-fix.ts
|
|
268
|
+
/**
|
|
269
|
+
* When the cursor is positioned after an inline atom node at the end of a line,
|
|
270
|
+
* browsers may display the cursor inside the atom.
|
|
271
|
+
*/
|
|
272
|
+
var atomCursorFix = ($cursor) => {
|
|
273
|
+
if (!($cursor.parentOffset === $cursor.parent.content.size)) return null;
|
|
274
|
+
const nodeBefore = $cursor.nodeBefore;
|
|
275
|
+
if (nodeBefore && nodeBefore.isInline && nodeBefore.isAtom && !nodeBefore.isText) return {};
|
|
276
|
+
return null;
|
|
277
|
+
};
|
|
278
|
+
var RteCursorFixFeatureImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
279
|
+
constructor(..._args) {
|
|
280
|
+
super(..._args);
|
|
281
|
+
this.name = "RteCursorFix";
|
|
267
282
|
}
|
|
268
|
-
|
|
269
|
-
|
|
283
|
+
getPlugins(rte) {
|
|
284
|
+
const cursorFixes = [atomCursorFix];
|
|
285
|
+
for (const markType of Object.values(rte.schema.marks)) {
|
|
286
|
+
const spec = markType.spec;
|
|
287
|
+
if (spec.cursorFix) cursorFixes.push(spec.cursorFix);
|
|
288
|
+
}
|
|
289
|
+
return [this.contribution(new prosemirror_state.Plugin({ props: { decorations: (state) => {
|
|
290
|
+
const { $cursor } = state.selection;
|
|
291
|
+
if (!$cursor) return null;
|
|
292
|
+
let cursorFix = null;
|
|
293
|
+
for (const fn of cursorFixes) {
|
|
294
|
+
const result = fn($cursor, state);
|
|
295
|
+
if (result) Object.assign(cursorFix ??= {}, result);
|
|
296
|
+
}
|
|
297
|
+
if (!cursorFix) return null;
|
|
298
|
+
return prosemirror_view.DecorationSet.create(state.doc, [prosemirror_view.Decoration.widget($cursor.pos, () => {
|
|
299
|
+
const span = document.createElement("span");
|
|
300
|
+
span.textContent = "";
|
|
301
|
+
for (const [prop, value] of Object.entries(cursorFix)) span.style.setProperty(prop, value);
|
|
302
|
+
return span;
|
|
303
|
+
}, { side: -1 })]);
|
|
304
|
+
} } }))];
|
|
270
305
|
}
|
|
271
|
-
|
|
272
|
-
|
|
306
|
+
};
|
|
307
|
+
require_slottable_request.featureFacade(RteCursorFixFeatureImpl);
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/lib/rich-text-editor/rte/features/internal/core.ts
|
|
310
|
+
/**
|
|
311
|
+
* Plugin to bring state from the host web component into ProseMirror.
|
|
312
|
+
*/
|
|
313
|
+
var hostBridgePlugin = new prosemirror_state.Plugin({ state: {
|
|
314
|
+
init() {
|
|
315
|
+
return null;
|
|
316
|
+
},
|
|
317
|
+
apply(tr, value) {
|
|
318
|
+
const meta = tr.getMeta(hostBridgePlugin);
|
|
319
|
+
if (meta) return meta;
|
|
320
|
+
else return value;
|
|
273
321
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
322
|
+
} });
|
|
323
|
+
var RteCoreImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
324
|
+
constructor(..._args) {
|
|
325
|
+
super(..._args);
|
|
326
|
+
this.name = "RteCore";
|
|
327
|
+
this.disabled = new FeatureState(false);
|
|
328
|
+
this.scrollThreshold = void 0;
|
|
329
|
+
this.scrollMargin = void 0;
|
|
330
|
+
}
|
|
331
|
+
getStyles() {
|
|
332
|
+
return [
|
|
333
|
+
this.contribution(prosemirror_default),
|
|
334
|
+
this.contribution(core_style_default),
|
|
335
|
+
this.contribution(ui_style_default)
|
|
336
|
+
];
|
|
337
|
+
}
|
|
338
|
+
getPlugins(rte) {
|
|
339
|
+
const enterKeyChainCommands = (0, prosemirror_commands.chainCommands)(prosemirror_commands.newlineInCode, prosemirror_commands.createParagraphNear, prosemirror_commands.liftEmptyBlock, (0, prosemirror_commands.splitBlockAs)((node, atEnd, $from) => {
|
|
340
|
+
if (!atEnd) return {
|
|
341
|
+
type: node.type,
|
|
342
|
+
attrs: node.attrs
|
|
343
|
+
};
|
|
344
|
+
return {
|
|
345
|
+
type: defaultTextblockForMatch($from.node($from.depth - 1).contentMatchAt($from.indexAfter($from.depth - 1))),
|
|
346
|
+
attrs: rte.textblockAttrs.extractFromNode(node)
|
|
347
|
+
};
|
|
348
|
+
}));
|
|
349
|
+
return [
|
|
350
|
+
this.contribution(this.disabled.plugin),
|
|
351
|
+
this.contribution(new prosemirror_state.Plugin({
|
|
352
|
+
props: {
|
|
353
|
+
editable: () => !this.disabled.getValue(rte),
|
|
354
|
+
handleDOMEvents: { click: (_view, event) => {
|
|
355
|
+
if (this.disabled.getValue(rte)) {
|
|
356
|
+
event.preventDefault();
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
return false;
|
|
360
|
+
} }
|
|
361
|
+
},
|
|
362
|
+
view: (view) => {
|
|
363
|
+
const popovers = view.dom.getRootNode().querySelector(".popovers");
|
|
364
|
+
const updateDisabled = () => {
|
|
365
|
+
const disabled = this.disabled.getValue(rte);
|
|
366
|
+
popovers.classList.toggle("popovers--disabled", disabled);
|
|
367
|
+
view.dom.parentElement.classList.toggle("editor--disabled", disabled);
|
|
368
|
+
};
|
|
369
|
+
updateDisabled();
|
|
370
|
+
return { update: () => {
|
|
371
|
+
updateDisabled();
|
|
372
|
+
} };
|
|
373
|
+
}
|
|
374
|
+
})),
|
|
375
|
+
this.contribution((0, prosemirror_keymap.keymap)({
|
|
376
|
+
...prosemirror_commands.baseKeymap,
|
|
377
|
+
Enter: enterKeyChainCommands,
|
|
378
|
+
"Shift-Enter": enterKeyChainCommands
|
|
379
|
+
})),
|
|
380
|
+
this.contribution((0, prosemirror_dropcursor.dropCursor)()),
|
|
381
|
+
this.contribution((0, prosemirror_gapcursor.gapCursor)()),
|
|
382
|
+
this.contribution(hostBridgePlugin)
|
|
383
|
+
];
|
|
384
|
+
}
|
|
385
|
+
getFeatures() {
|
|
386
|
+
return [
|
|
387
|
+
this,
|
|
388
|
+
new RteForeignHtmlFeatureImpl(),
|
|
389
|
+
new RteCursorFixFeatureImpl()
|
|
390
|
+
];
|
|
280
391
|
}
|
|
281
392
|
};
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
393
|
+
require_slottable_request.featureFacade(RteCoreImpl);
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/lib/rich-text-editor/rte/utils/sanitization.ts
|
|
396
|
+
var DEFAULT_ALLOWED_URI_REGEXP = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
397
|
+
var ALLOWED_URI_REGEXP_WITH_BLOB = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|blob):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
398
|
+
var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
399
|
+
var domPurifyConfig = { ALLOWED_URI_REGEXP: ALLOWED_URI_REGEXP_WITH_BLOB };
|
|
400
|
+
/**
|
|
401
|
+
* Sanitize potentially dangerous URLs, like "javascript:", in anchor href attributes.
|
|
402
|
+
* Returns empty string if the URL is unsafe.
|
|
403
|
+
*/
|
|
404
|
+
var sanitizeLinkHref = (url) => {
|
|
405
|
+
if (!DEFAULT_ALLOWED_URI_REGEXP.test(url.replace(ATTR_WHITESPACE, ""))) return "";
|
|
291
406
|
const anchor = document.createElement("a");
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
return anchor;
|
|
407
|
+
anchor.setAttribute("href", url);
|
|
408
|
+
/* v8 ignore next -- since href is already validated it's probably always present @preserve */
|
|
409
|
+
return dompurify.default.sanitize(anchor, {
|
|
410
|
+
RETURN_DOM: true,
|
|
411
|
+
...domPurifyConfig
|
|
412
|
+
}).querySelector("a").getAttribute("href") ?? "";
|
|
299
413
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
tooltip.anchor = enabled ? props.anchor : void 0;
|
|
312
|
-
});
|
|
313
|
-
const wrapper = createDiv(ctx, {
|
|
314
|
-
className: "ui-tooltip-wrapper",
|
|
315
|
-
slot: props.slot,
|
|
316
|
-
children: [props.anchor, tooltip]
|
|
317
|
-
});
|
|
318
|
-
wrapperTargets.set(wrapper, props.anchor);
|
|
319
|
-
return wrapper;
|
|
414
|
+
/**
|
|
415
|
+
* Sanitize potentially dangerous URLs, like "javascript:", in image src attributes.
|
|
416
|
+
* Returns empty string if the URL is unsafe.
|
|
417
|
+
*/
|
|
418
|
+
var sanitizeImageSrc = (url) => {
|
|
419
|
+
const img = document.createElement("img");
|
|
420
|
+
img.setAttribute("src", url);
|
|
421
|
+
return dompurify.default.sanitize(img, {
|
|
422
|
+
RETURN_DOM: true,
|
|
423
|
+
...domPurifyConfig
|
|
424
|
+
}).querySelector("img").getAttribute("src") ?? "";
|
|
320
425
|
};
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
appearance,
|
|
333
|
-
disabled,
|
|
334
|
-
icon: props.icon,
|
|
335
|
-
autofocus: props.autofocus,
|
|
336
|
-
connotation,
|
|
337
|
-
[props.icon ? "ariaLabel" : "label"]: props.label,
|
|
338
|
-
pressed: () => Boolean(ctx.evalProp(props.active)),
|
|
339
|
-
ariaPressed: props.active !== void 0 ? () => ctx.evalProp(props.active) ? "true" : "false" : void 0
|
|
340
|
-
}, [on("click", props.onClick, (onClick) => () => {
|
|
341
|
-
if (!onClick() && ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
342
|
-
})]);
|
|
343
|
-
return createOptionalTooltip(ctx, {
|
|
344
|
-
enabled: () => Boolean(ctx.evalProp(props.icon) && !ctx.evalProp(props.noTooltip) && !disabled()),
|
|
345
|
-
label: props.label,
|
|
346
|
-
anchor: button,
|
|
347
|
-
slot: props.slot
|
|
348
|
-
});
|
|
349
|
-
};
|
|
350
|
-
var createMenu = (ctx, props) => {
|
|
351
|
-
const menu = ctx.rte.createComponent(require_definition$4.Menu);
|
|
352
|
-
ctx.bindToEl(menu, {
|
|
353
|
-
className: "ui-menu",
|
|
354
|
-
autoDismiss: true,
|
|
355
|
-
ariaLabel: props.label,
|
|
356
|
-
anchor: wrapperTargets.get(props.trigger) ?? props.trigger,
|
|
357
|
-
placement: ctx.props.popupPlacement,
|
|
358
|
-
offset: () => ctx.evalProp(ctx.props.menuOffset) ?? null
|
|
359
|
-
}, [], props.children);
|
|
360
|
-
const fragment = document.createDocumentFragment();
|
|
361
|
-
fragment.appendChild(props.trigger);
|
|
362
|
-
fragment.appendChild(menu);
|
|
363
|
-
return fragment;
|
|
364
|
-
};
|
|
365
|
-
var createMenuItem = (ctx, props) => {
|
|
366
|
-
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
|
|
367
|
-
const item = ctx.rte.createComponent(require_definition$3.MenuItem);
|
|
368
|
-
ctx.bindToEl(item, {
|
|
369
|
-
text: props.text,
|
|
370
|
-
checked: props.checked,
|
|
371
|
-
disabled,
|
|
372
|
-
controlType: "radio",
|
|
373
|
-
checkedAppearance: "tick-only"
|
|
374
|
-
}, [on("change", props.onSelect, (onSelect) => () => {
|
|
375
|
-
if (item.checked && !item.disabled) {
|
|
376
|
-
if (ctx.evalProp(props.checked) !== item.checked) {
|
|
377
|
-
onSelect();
|
|
378
|
-
if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
})]);
|
|
382
|
-
return item;
|
|
383
|
-
};
|
|
384
|
-
var createButtonGroup = (ctx, props) => createDiv(ctx, {
|
|
385
|
-
slot: props.slot,
|
|
386
|
-
className: "ui-button-group",
|
|
387
|
-
children: props.children
|
|
426
|
+
/**
|
|
427
|
+
* Escapes a CSS value for insertion into style attribute.
|
|
428
|
+
* E.g. "15px; background: red" => "15px"
|
|
429
|
+
*/
|
|
430
|
+
var escapeCssProperty = (value) => value.replace(/[;!].*/, "");
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/lib/rich-text-editor/rte/html-parser.ts
|
|
433
|
+
var copy = (obj) => ({ ...obj });
|
|
434
|
+
var parseRulesFromSchema = (schema) => ({
|
|
435
|
+
nodes: Object.fromEntries(Object.keys(schema.nodes).map((name) => [name, (schema.nodes[name].spec.parseDOM ?? []).map(copy)])),
|
|
436
|
+
marks: Object.fromEntries(Object.keys(schema.marks).map((name) => [name, (schema.marks[name].spec.parseDOM ?? []).map(copy)]))
|
|
388
437
|
});
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
438
|
+
var RteHtmlParser = class {
|
|
439
|
+
constructor(config, options) {
|
|
440
|
+
this[require_slottable_request.impl] = new RteHtmlParserImpl(config[require_slottable_request.impl], options);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Converts an HTML string to an RteDocument.
|
|
444
|
+
*/
|
|
445
|
+
parseDocument(html, options) {
|
|
446
|
+
return this[require_slottable_request.impl].parser.parse(this.parseHtml(html, options), { preserveWhitespace: true }).toJSON();
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Converts an HTML string to an RteFragment.
|
|
450
|
+
*/
|
|
451
|
+
parseFragment(html, options) {
|
|
452
|
+
return this[require_slottable_request.impl].parser.parseSlice(this.parseHtml(html, options), { preserveWhitespace: true }).content.toJSON() ?? [];
|
|
453
|
+
}
|
|
454
|
+
parseHtml(html, options) {
|
|
455
|
+
const dom = dompurify.default.sanitize(html, {
|
|
456
|
+
RETURN_DOM: true,
|
|
457
|
+
...domPurifyConfig
|
|
458
|
+
});
|
|
459
|
+
const container = document.createDocumentFragment();
|
|
460
|
+
container.appendChild(dom);
|
|
461
|
+
options?.modifyDom?.(container);
|
|
462
|
+
return container;
|
|
401
463
|
}
|
|
402
|
-
});
|
|
403
|
-
var createOption = (ctx, props) => {
|
|
404
|
-
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
|
|
405
|
-
const option = ctx.rte.createComponent(require_definition$7.ListboxOption);
|
|
406
|
-
ctx.bindToEl(option, {
|
|
407
|
-
value: props.value,
|
|
408
|
-
text: props.text,
|
|
409
|
-
disabled
|
|
410
|
-
});
|
|
411
|
-
return option;
|
|
412
464
|
};
|
|
413
|
-
var
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
465
|
+
var RteHtmlParserImpl = class {
|
|
466
|
+
constructor(config, options) {
|
|
467
|
+
const rules = parseRulesFromSchema(config.schema);
|
|
468
|
+
options?.modifyParseRules?.(rules);
|
|
469
|
+
this.parser = buildDomParser(config.schema, rules);
|
|
470
|
+
}
|
|
471
|
+
transform(html) {
|
|
472
|
+
return dompurify.default.sanitize(html);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
var buildDomParser = (schema, { marks, nodes }) => {
|
|
476
|
+
const parserRules = [];
|
|
477
|
+
const priority = (rule) => rule.priority ?? 50;
|
|
478
|
+
function insert(rule) {
|
|
479
|
+
let i = 0;
|
|
480
|
+
for (; i < parserRules.length; i++) {
|
|
481
|
+
const next = parserRules[i];
|
|
482
|
+
if (priority(next) < priority(rule)) break;
|
|
427
483
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
select.addEventListener("vwc-popup:open", () => {
|
|
434
|
-
hideTooltip = true;
|
|
435
|
-
ctx.updateBindings();
|
|
436
|
-
});
|
|
437
|
-
select.addEventListener("vwc-popup:close", () => {
|
|
438
|
-
hideTooltip = false;
|
|
439
|
-
ctx.updateBindings();
|
|
484
|
+
parserRules.splice(i, 0, rule);
|
|
485
|
+
}
|
|
486
|
+
for (const name in marks) marks[name]?.forEach((rule) => {
|
|
487
|
+
insert(rule = copy(rule));
|
|
488
|
+
if (!(rule.mark || rule.ignore || rule.clearMark)) rule.mark = name;
|
|
440
489
|
});
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
anchor: select
|
|
490
|
+
for (const name in nodes) nodes[name]?.forEach((rule) => {
|
|
491
|
+
insert(rule = copy(rule));
|
|
492
|
+
if (!(rule.node || rule.ignore || rule.mark)) rule.node = name;
|
|
445
493
|
});
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
ctx.bindToEl(divider, {
|
|
450
|
-
className: "ui-divider",
|
|
451
|
-
orientation: "vertical"
|
|
494
|
+
parserRules.push({
|
|
495
|
+
tag: "br",
|
|
496
|
+
closeParent: true
|
|
452
497
|
});
|
|
453
|
-
return
|
|
454
|
-
};
|
|
455
|
-
var createTextField = (ctx, props) => {
|
|
456
|
-
const textField = ctx.rte.createComponent(require_definition$5.TextField);
|
|
457
|
-
ctx.bindToEl(textField, {
|
|
458
|
-
label: props.label,
|
|
459
|
-
value: props.value,
|
|
460
|
-
placeholder: props.placeholder,
|
|
461
|
-
slot: props.slot,
|
|
462
|
-
autofocus: props.autofocus,
|
|
463
|
-
type: props.type,
|
|
464
|
-
helperText: props.helperText
|
|
465
|
-
}, [on("input", props.onInput, (onInput) => () => {
|
|
466
|
-
onInput(textField.value);
|
|
467
|
-
})]);
|
|
468
|
-
return textField;
|
|
498
|
+
return new prosemirror_model.DOMParser(schema, parserRules);
|
|
469
499
|
};
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/lib/rich-text-editor/rte/html-serializer.ts
|
|
502
|
+
var RteHtmlSerializer = class {
|
|
503
|
+
constructor(config, options) {
|
|
504
|
+
this[require_slottable_request.impl] = new RteHtmlSerializerImpl(config[require_slottable_request.impl], options);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Converts an RteDocument to an HTML string.
|
|
508
|
+
*/
|
|
509
|
+
serializeDocument(doc, options) {
|
|
510
|
+
return this[require_slottable_request.impl].serializeFragment(doc.content, options);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Converts an RteFragment to an HTML string.
|
|
514
|
+
*/
|
|
515
|
+
serializeFragment(fragment, options) {
|
|
516
|
+
return this[require_slottable_request.impl].serializeFragment(fragment, options);
|
|
517
|
+
}
|
|
474
518
|
};
|
|
475
|
-
var
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
listeners.length = 0;
|
|
483
|
-
currentEl = null;
|
|
519
|
+
var RteHtmlSerializerImpl = class RteHtmlSerializerImpl {
|
|
520
|
+
constructor(config, options) {
|
|
521
|
+
this.config = config;
|
|
522
|
+
const serializers = RteHtmlSerializerImpl.domSerializersFromSchema(config.schema);
|
|
523
|
+
Object.assign(serializers.nodes, options?.serializers?.nodes ?? {});
|
|
524
|
+
Object.assign(serializers.marks, options?.serializers?.marks ?? {});
|
|
525
|
+
this.serializer = new prosemirror_model.DOMSerializer(serializers.nodes, serializers.marks);
|
|
484
526
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
for (const
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
494
|
-
};
|
|
495
|
-
el.addEventListener(type, listener);
|
|
496
|
-
listeners.push({
|
|
497
|
-
el,
|
|
498
|
-
type,
|
|
499
|
-
handler: listener
|
|
500
|
-
});
|
|
527
|
+
static domSerializersFromSchema(schema) {
|
|
528
|
+
const result = {
|
|
529
|
+
nodes: {},
|
|
530
|
+
marks: {}
|
|
531
|
+
};
|
|
532
|
+
for (const name in schema.marks) {
|
|
533
|
+
const toDOM = schema.marks[name].spec.toDOM;
|
|
534
|
+
if (toDOM) result.marks[name] = toDOM;
|
|
501
535
|
}
|
|
536
|
+
for (const name in schema.nodes) {
|
|
537
|
+
const toDOM = schema.nodes[name].spec.serializeToDOM ?? schema.nodes[name].spec.toDOM;
|
|
538
|
+
if (toDOM) result.nodes[name] = toDOM;
|
|
539
|
+
}
|
|
540
|
+
result.nodes.text = (node) => document.createTextNode(node.text);
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
543
|
+
serializeFragment(fragment, options) {
|
|
544
|
+
const parsedFragment = prosemirror_model.Fragment.fromJSON(this.config.schema, fragment);
|
|
545
|
+
const serializedFragment = this.serializer.serializeFragment(parsedFragment);
|
|
546
|
+
const container = document.createDocumentFragment();
|
|
547
|
+
container.appendChild(serializedFragment);
|
|
548
|
+
options?.modifyDom?.(container);
|
|
549
|
+
const output = document.createElement("div");
|
|
550
|
+
output.appendChild(container);
|
|
551
|
+
return output.innerHTML;
|
|
502
552
|
}
|
|
503
|
-
const processSlot = () => {
|
|
504
|
-
const first = slot.assignedElements({ flatten: true })[0];
|
|
505
|
-
if (first === currentEl) return;
|
|
506
|
-
cleanup();
|
|
507
|
-
if (first) {
|
|
508
|
-
currentEl = first;
|
|
509
|
-
applyPropsAndEvents(first);
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
slot.addEventListener("slotchange", processSlot);
|
|
513
|
-
queueMicrotask(processSlot);
|
|
514
|
-
return slot;
|
|
515
553
|
};
|
|
516
554
|
//#endregion
|
|
517
|
-
//#region src/lib/rich-text-editor/rte/
|
|
518
|
-
var
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
555
|
+
//#region src/lib/rich-text-editor/rte/instance.ts
|
|
556
|
+
var parseDocument = (schema, doc) => {
|
|
557
|
+
const node = schema.topNodeType.createAndFill(null, doc ? prosemirror_model.Fragment.fromJSON(schema, doc.content) : null);
|
|
558
|
+
if (!node) throw new Error("Document could not be parsed");
|
|
559
|
+
node.check();
|
|
560
|
+
return node;
|
|
561
|
+
};
|
|
562
|
+
var RteInstance = class {
|
|
563
|
+
constructor(config, options) {
|
|
564
|
+
this.options = options;
|
|
565
|
+
this.feature = (Feature, featureId) => {
|
|
566
|
+
return this[require_slottable_request.impl].getPublicInterface(Feature, featureId);
|
|
567
|
+
};
|
|
568
|
+
this[require_slottable_request.impl] = new RteInstanceImpl(this, config, options);
|
|
522
569
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}))];
|
|
570
|
+
/**
|
|
571
|
+
* Returns the current document state.
|
|
572
|
+
*/
|
|
573
|
+
getDocument() {
|
|
574
|
+
return this[require_slottable_request.impl].state.doc.toJSON();
|
|
529
575
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
icon: "undo-line",
|
|
536
|
-
disabled: (ctx) => !(0, prosemirror_history.undo)(ctx.view.state),
|
|
537
|
-
onClick: () => {
|
|
538
|
-
const { state, dispatch } = ctx.view;
|
|
539
|
-
(0, prosemirror_history.undo)(state, dispatch);
|
|
540
|
-
}
|
|
541
|
-
})
|
|
542
|
-
}, 1), this.contribution({
|
|
543
|
-
section: "history",
|
|
544
|
-
render: (ctx) => createButton(ctx, {
|
|
545
|
-
label: (ctx) => ctx.rte.getLocale().richTextEditor.redo,
|
|
546
|
-
icon: "redo-line",
|
|
547
|
-
disabled: (ctx) => !(0, prosemirror_history.redo)(ctx.view.state),
|
|
548
|
-
onClick: () => {
|
|
549
|
-
const { state, dispatch } = ctx.view;
|
|
550
|
-
(0, prosemirror_history.redo)(state, dispatch);
|
|
551
|
-
}
|
|
552
|
-
})
|
|
553
|
-
}, 2)];
|
|
576
|
+
/**
|
|
577
|
+
* Reset the editor to its initial state. Optionally, an initial document can be provided.
|
|
578
|
+
*/
|
|
579
|
+
reset(initialDocument) {
|
|
580
|
+
this[require_slottable_request.impl].reset(initialDocument);
|
|
554
581
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
582
|
+
/**
|
|
583
|
+
* Replaces the current selection with the given content.
|
|
584
|
+
* If no text is selected, this inserts the content at the cursor position.
|
|
585
|
+
*/
|
|
586
|
+
replaceSelection(content, options) {
|
|
587
|
+
const { state, tr, schema, dispatchTransaction } = this[require_slottable_request.impl];
|
|
588
|
+
tr.replaceSelection(new prosemirror_model.Slice(prosemirror_model.Fragment.fromJSON(schema, content), 0, 0));
|
|
589
|
+
tr.doc.check();
|
|
590
|
+
const $from = tr.doc.resolve(tr.mapping.map(state.selection.from));
|
|
591
|
+
const $to = tr.doc.resolve(tr.selection.to);
|
|
592
|
+
const [$head, $anchor] = options?.cursorPlacement === "start" ? [$from, $to] : [$to, $from];
|
|
593
|
+
if (options?.selectContent) tr.setSelection(state.selection instanceof prosemirror_state.AllSelection ? new prosemirror_state.AllSelection(tr.doc) : prosemirror_state.TextSelection.between($anchor, $head));
|
|
594
|
+
else tr.setSelection(prosemirror_state.TextSelection.between($head, $head));
|
|
595
|
+
dispatchTransaction(tr);
|
|
562
596
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
}
|
|
597
|
+
/**
|
|
598
|
+
* Replaces the entire document with the given new document.
|
|
599
|
+
* Unlike reset, this preserves the rest of the editor state. The undo history is preserved, so the user can undo the replacement.
|
|
600
|
+
*/
|
|
601
|
+
replaceDocument(newDocument, options) {
|
|
602
|
+
const { state, tr, schema, dispatchTransaction } = this[require_slottable_request.impl];
|
|
603
|
+
tr.replaceWith(0, state.doc.content.size, parseDocument(schema, newDocument));
|
|
604
|
+
if (options?.selectContent) tr.setSelection(new prosemirror_state.AllSelection(tr.doc));
|
|
605
|
+
else if (options?.cursorPlacement === "end") tr.setSelection(prosemirror_state.TextSelection.atEnd(tr.doc));
|
|
606
|
+
else tr.setSelection(prosemirror_state.TextSelection.atStart(tr.doc));
|
|
607
|
+
dispatchTransaction(tr);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Scrolls the cursor into view.
|
|
611
|
+
* Has no effect if the editor is not currently mounted.
|
|
612
|
+
*/
|
|
613
|
+
scrollIntoView() {
|
|
614
|
+
const instance = this[require_slottable_request.impl];
|
|
615
|
+
if (!instance.view) return;
|
|
616
|
+
instance.dispatchTransaction(instance.tr.scrollIntoView());
|
|
569
617
|
}
|
|
570
618
|
};
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
*/
|
|
577
|
-
var atomCursorFix = ($cursor) => {
|
|
578
|
-
if (!($cursor.parentOffset === $cursor.parent.content.size)) return null;
|
|
579
|
-
const nodeBefore = $cursor.nodeBefore;
|
|
580
|
-
if (nodeBefore && nodeBefore.isInline && nodeBefore.isAtom && !nodeBefore.isText) return {};
|
|
581
|
-
return null;
|
|
582
|
-
};
|
|
583
|
-
var RteCursorFixFeatureImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
584
|
-
constructor(..._args) {
|
|
585
|
-
super(..._args);
|
|
586
|
-
this.name = "RteCursorFix";
|
|
619
|
+
var RteInstanceImpl = class {
|
|
620
|
+
getFeature(name) {
|
|
621
|
+
const f = this.config.featureMap.get(name);
|
|
622
|
+
if (!f) throw new Error(`Feature not found: ${name}`);
|
|
623
|
+
return f;
|
|
587
624
|
}
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if (
|
|
625
|
+
getPublicInterface(Feature, featureId) {
|
|
626
|
+
const instances = this.config.featureFacadesMap.get(Feature);
|
|
627
|
+
if (!instances || instances.length === 0) throw new Error(`Feature not found`);
|
|
628
|
+
if (instances[0].featureId !== void 0) {
|
|
629
|
+
if (featureId === void 0) throw new Error(`No featureId provided for multi-instance feature.`);
|
|
630
|
+
const instance = instances.find((f) => f.featureId === featureId);
|
|
631
|
+
if (!instance) throw new Error(`Feature with id "${featureId}" not found`);
|
|
632
|
+
return instance.getPublicInterface(this);
|
|
593
633
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (!$cursor) return null;
|
|
597
|
-
let cursorFix = null;
|
|
598
|
-
for (const fn of cursorFixes) {
|
|
599
|
-
const result = fn($cursor, state);
|
|
600
|
-
if (result) Object.assign(cursorFix ??= {}, result);
|
|
601
|
-
}
|
|
602
|
-
if (!cursorFix) return null;
|
|
603
|
-
return prosemirror_view.DecorationSet.create(state.doc, [prosemirror_view.Decoration.widget($cursor.pos, () => {
|
|
604
|
-
const span = document.createElement("span");
|
|
605
|
-
span.textContent = "";
|
|
606
|
-
for (const [prop, value] of Object.entries(cursorFix)) span.style.setProperty(prop, value);
|
|
607
|
-
return span;
|
|
608
|
-
}, { side: -1 })]);
|
|
609
|
-
} } }))];
|
|
634
|
+
if (featureId !== void 0) throw new Error(`Feature does not support featureId`);
|
|
635
|
+
return instances[0].getPublicInterface(this);
|
|
610
636
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
637
|
+
constructor(instanceFacade, configFacade, options) {
|
|
638
|
+
this.options = options;
|
|
639
|
+
this.view = null;
|
|
640
|
+
this.dispatchTransaction = (tr) => {
|
|
641
|
+
const prevState = this.state;
|
|
642
|
+
this.state = this.state.apply(tr);
|
|
643
|
+
this.view?.updateState(this.state);
|
|
644
|
+
if (prevState.doc !== this.state.doc) this.options?.onChange?.();
|
|
645
|
+
return this.state;
|
|
646
|
+
};
|
|
647
|
+
this.facade = instanceFacade;
|
|
648
|
+
const config = configFacade[require_slottable_request.impl];
|
|
649
|
+
this.config = config;
|
|
650
|
+
this.schema = config.schema;
|
|
651
|
+
this.textblockAttrs = config.textblockAttrs;
|
|
652
|
+
this.features = config.features;
|
|
653
|
+
this.foreignHtmlParser = options?.foreignHtmlParser ?? new RteHtmlParser(configFacade);
|
|
654
|
+
this.foreignHtmlSerializer = options?.foreignHtmlSerializer ?? new RteHtmlSerializer(configFacade);
|
|
655
|
+
this.styles = new _microsoft_fast_element.ElementStyles(require_slottable_request.sortedContributions(config.features.flatMap((f) => f.getStyles())));
|
|
656
|
+
this.initState(options?.initialDocument);
|
|
626
657
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
658
|
+
initState(initialDoc) {
|
|
659
|
+
this.state = prosemirror_state.EditorState.create({
|
|
660
|
+
doc: parseDocument(this.schema, initialDoc),
|
|
661
|
+
schema: this.config.schema,
|
|
662
|
+
plugins: require_slottable_request.sortedContributions(this.config.features.flatMap((feature) => feature.getPlugins(this)))
|
|
663
|
+
});
|
|
633
664
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
];
|
|
665
|
+
reset(initialDocument) {
|
|
666
|
+
const currentHostState = hostBridgePlugin.getState(this.state);
|
|
667
|
+
this.initState(initialDocument);
|
|
668
|
+
this.updateHostState(currentHostState);
|
|
669
|
+
this.view?.updateState(this.state);
|
|
640
670
|
}
|
|
641
|
-
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}
|
|
651
|
-
})
|
|
652
|
-
return [
|
|
653
|
-
this.contribution(this.disabled.plugin),
|
|
654
|
-
this.contribution(new prosemirror_state.Plugin({
|
|
655
|
-
props: {
|
|
656
|
-
editable: () => !this.disabled.getValue(rte),
|
|
657
|
-
handleDOMEvents: { click: (_view, event) => {
|
|
658
|
-
if (this.disabled.getValue(rte)) {
|
|
659
|
-
event.preventDefault();
|
|
660
|
-
return true;
|
|
661
|
-
}
|
|
662
|
-
return false;
|
|
663
|
-
} }
|
|
664
|
-
},
|
|
665
|
-
view: (view) => {
|
|
666
|
-
const popovers = view.dom.getRootNode().querySelector(".popovers");
|
|
667
|
-
const updateDisabled = () => {
|
|
668
|
-
const disabled = this.disabled.getValue(rte);
|
|
669
|
-
popovers.classList.toggle("popovers--disabled", disabled);
|
|
670
|
-
view.dom.parentElement.classList.toggle("editor--disabled", disabled);
|
|
671
|
-
};
|
|
672
|
-
updateDisabled();
|
|
673
|
-
return { update: () => {
|
|
674
|
-
updateDisabled();
|
|
675
|
-
} };
|
|
676
|
-
}
|
|
677
|
-
})),
|
|
678
|
-
this.contribution((0, prosemirror_keymap.keymap)({
|
|
679
|
-
...prosemirror_commands.baseKeymap,
|
|
680
|
-
Enter: enterKeyChainCommands,
|
|
681
|
-
"Shift-Enter": enterKeyChainCommands
|
|
682
|
-
})),
|
|
683
|
-
this.contribution((0, prosemirror_dropcursor.dropCursor)()),
|
|
684
|
-
this.contribution((0, prosemirror_gapcursor.gapCursor)()),
|
|
685
|
-
this.contribution(hostBridgePlugin)
|
|
686
|
-
];
|
|
687
|
-
}
|
|
688
|
-
getFeatures() {
|
|
689
|
-
return [
|
|
690
|
-
this,
|
|
691
|
-
new RteHistoryFeatureImpl(),
|
|
692
|
-
new RteForeignHtmlFeatureImpl(),
|
|
693
|
-
new RteCursorFixFeatureImpl()
|
|
694
|
-
];
|
|
695
|
-
}
|
|
696
|
-
};
|
|
697
|
-
require_slottable_request.featureFacade(RteCoreImpl);
|
|
698
|
-
//#endregion
|
|
699
|
-
//#region src/lib/rich-text-editor/rte/utils/sanitization.ts
|
|
700
|
-
var DEFAULT_ALLOWED_URI_REGEXP = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
701
|
-
var ALLOWED_URI_REGEXP_WITH_BLOB = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|blob):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
702
|
-
var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
703
|
-
var domPurifyConfig = { ALLOWED_URI_REGEXP: ALLOWED_URI_REGEXP_WITH_BLOB };
|
|
704
|
-
/**
|
|
705
|
-
* Sanitize potentially dangerous URLs, like "javascript:", in anchor href attributes.
|
|
706
|
-
* Returns empty string if the URL is unsafe.
|
|
707
|
-
*/
|
|
708
|
-
var sanitizeLinkHref = (url) => {
|
|
709
|
-
if (!DEFAULT_ALLOWED_URI_REGEXP.test(url.replace(ATTR_WHITESPACE, ""))) return "";
|
|
710
|
-
const anchor = document.createElement("a");
|
|
711
|
-
anchor.setAttribute("href", url);
|
|
712
|
-
/* v8 ignore next -- since href is already validated it's probably always present @preserve */
|
|
713
|
-
return dompurify.default.sanitize(anchor, {
|
|
714
|
-
RETURN_DOM: true,
|
|
715
|
-
...domPurifyConfig
|
|
716
|
-
}).querySelector("a").getAttribute("href") ?? "";
|
|
717
|
-
};
|
|
718
|
-
/**
|
|
719
|
-
* Sanitize potentially dangerous URLs, like "javascript:", in image src attributes.
|
|
720
|
-
* Returns empty string if the URL is unsafe.
|
|
721
|
-
*/
|
|
722
|
-
var sanitizeImageSrc = (url) => {
|
|
723
|
-
const img = document.createElement("img");
|
|
724
|
-
img.setAttribute("src", url);
|
|
725
|
-
return dompurify.default.sanitize(img, {
|
|
726
|
-
RETURN_DOM: true,
|
|
727
|
-
...domPurifyConfig
|
|
728
|
-
}).querySelector("img").getAttribute("src") ?? "";
|
|
729
|
-
};
|
|
730
|
-
/**
|
|
731
|
-
* Escapes a CSS value for insertion into style attribute.
|
|
732
|
-
* E.g. "15px; background: red" => "15px"
|
|
733
|
-
*/
|
|
734
|
-
var escapeCssProperty = (value) => value.replace(/[;!].*/, "");
|
|
735
|
-
//#endregion
|
|
736
|
-
//#region src/lib/rich-text-editor/rte/html-parser.ts
|
|
737
|
-
var copy = (obj) => ({ ...obj });
|
|
738
|
-
var parseRulesFromSchema = (schema) => ({
|
|
739
|
-
nodes: Object.fromEntries(Object.keys(schema.nodes).map((name) => [name, (schema.nodes[name].spec.parseDOM ?? []).map(copy)])),
|
|
740
|
-
marks: Object.fromEntries(Object.keys(schema.marks).map((name) => [name, (schema.marks[name].spec.parseDOM ?? []).map(copy)]))
|
|
741
|
-
});
|
|
742
|
-
var RteHtmlParser = class {
|
|
743
|
-
constructor(config, options) {
|
|
744
|
-
this[require_slottable_request.impl] = new RteHtmlParserImpl(config[require_slottable_request.impl], options);
|
|
671
|
+
createView(target) {
|
|
672
|
+
const core = this.config.featureMap.get("RteCore");
|
|
673
|
+
this.view = new prosemirror_view.EditorView((editor) => {
|
|
674
|
+
editor.part = "editor";
|
|
675
|
+
target.appendChild(editor);
|
|
676
|
+
}, {
|
|
677
|
+
state: this.state,
|
|
678
|
+
dispatchTransaction: this.dispatchTransaction,
|
|
679
|
+
...core?.scrollThreshold !== void 0 && { scrollThreshold: core.scrollThreshold },
|
|
680
|
+
...core?.scrollMargin !== void 0 && { scrollMargin: core.scrollMargin }
|
|
681
|
+
});
|
|
745
682
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
683
|
+
destroyViewIfNeeded() {
|
|
684
|
+
if (this.view) {
|
|
685
|
+
this.view.destroy();
|
|
686
|
+
this.view = null;
|
|
687
|
+
}
|
|
751
688
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
*/
|
|
755
|
-
parseFragment(html, options) {
|
|
756
|
-
return this[require_slottable_request.impl].parser.parseSlice(this.parseHtml(html, options), { preserveWhitespace: true }).content.toJSON() ?? [];
|
|
689
|
+
createComponent(type) {
|
|
690
|
+
return document.createElement(this.hostState().ctx.tagFor(type, true));
|
|
757
691
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
RETURN_DOM: true,
|
|
761
|
-
...domPurifyConfig
|
|
762
|
-
});
|
|
763
|
-
const container = document.createDocumentFragment();
|
|
764
|
-
container.appendChild(dom);
|
|
765
|
-
options?.modifyDom?.(container);
|
|
766
|
-
return container;
|
|
692
|
+
getLocale() {
|
|
693
|
+
return this.hostState().locale;
|
|
767
694
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
constructor(config, options) {
|
|
771
|
-
const rules = parseRulesFromSchema(config.schema);
|
|
772
|
-
options?.modifyParseRules?.(rules);
|
|
773
|
-
this.parser = buildDomParser(config.schema, rules);
|
|
695
|
+
get tr() {
|
|
696
|
+
return this.state.tr;
|
|
774
697
|
}
|
|
775
|
-
|
|
776
|
-
|
|
698
|
+
hostState() {
|
|
699
|
+
const state = hostBridgePlugin.getState(this.state);
|
|
700
|
+
if (!state) throw new Error("No host state available");
|
|
701
|
+
return state;
|
|
777
702
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
const parserRules = [];
|
|
781
|
-
const priority = (rule) => rule.priority ?? 50;
|
|
782
|
-
function insert(rule) {
|
|
783
|
-
let i = 0;
|
|
784
|
-
for (; i < parserRules.length; i++) {
|
|
785
|
-
const next = parserRules[i];
|
|
786
|
-
if (priority(next) < priority(rule)) break;
|
|
787
|
-
}
|
|
788
|
-
parserRules.splice(i, 0, rule);
|
|
703
|
+
updateHostState(hostState) {
|
|
704
|
+
this.dispatchTransaction(this.tr.setMeta(hostBridgePlugin, hostState));
|
|
789
705
|
}
|
|
790
|
-
for (const name in marks) marks[name]?.forEach((rule) => {
|
|
791
|
-
insert(rule = copy(rule));
|
|
792
|
-
if (!(rule.mark || rule.ignore || rule.clearMark)) rule.mark = name;
|
|
793
|
-
});
|
|
794
|
-
for (const name in nodes) nodes[name]?.forEach((rule) => {
|
|
795
|
-
insert(rule = copy(rule));
|
|
796
|
-
if (!(rule.node || rule.ignore || rule.mark)) rule.node = name;
|
|
797
|
-
});
|
|
798
|
-
parserRules.push({
|
|
799
|
-
tag: "br",
|
|
800
|
-
closeParent: true
|
|
801
|
-
});
|
|
802
|
-
return new prosemirror_model.DOMParser(schema, parserRules);
|
|
803
706
|
};
|
|
804
707
|
//#endregion
|
|
805
|
-
//#region src/lib/rich-text-editor/rte/
|
|
806
|
-
var
|
|
807
|
-
constructor(
|
|
808
|
-
this
|
|
708
|
+
//#region src/lib/rich-text-editor/rte/utils/textblock-attrs.ts
|
|
709
|
+
var TextblockAttrs = class {
|
|
710
|
+
constructor(specs) {
|
|
711
|
+
this.specs = specs;
|
|
712
|
+
this.attrs = {};
|
|
713
|
+
for (const spec of specs) this.attrs[spec.name] = { default: spec.default };
|
|
809
714
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
*/
|
|
813
|
-
serializeDocument(doc, options) {
|
|
814
|
-
return this[require_slottable_request.impl].serializeFragment(doc.content, options);
|
|
715
|
+
fromDOM(dom) {
|
|
716
|
+
return Object.assign({}, ...this.specs.map((s) => ({ [s.name]: s.fromDOM(dom) })));
|
|
815
717
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
*/
|
|
819
|
-
serializeFragment(fragment, options) {
|
|
820
|
-
return this[require_slottable_request.impl].serializeFragment(fragment, options);
|
|
718
|
+
getStyle(node) {
|
|
719
|
+
return this.specs.flatMap((s) => s.toStyles(node)).join("; ");
|
|
821
720
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
this.config = config;
|
|
826
|
-
const serializers = RteHtmlSerializerImpl.domSerializersFromSchema(config.schema);
|
|
827
|
-
Object.assign(serializers.nodes, options?.serializers?.nodes ?? {});
|
|
828
|
-
Object.assign(serializers.marks, options?.serializers?.marks ?? {});
|
|
829
|
-
this.serializer = new prosemirror_model.DOMSerializer(serializers.nodes, serializers.marks);
|
|
721
|
+
getDOMAttrsProperties(node) {
|
|
722
|
+
if (!this.specs.length) return {};
|
|
723
|
+
return { style: this.getStyle(node) };
|
|
830
724
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
marks: {}
|
|
835
|
-
};
|
|
836
|
-
for (const name in schema.marks) {
|
|
837
|
-
const toDOM = schema.marks[name].spec.toDOM;
|
|
838
|
-
if (toDOM) result.marks[name] = toDOM;
|
|
839
|
-
}
|
|
840
|
-
for (const name in schema.nodes) {
|
|
841
|
-
const toDOM = schema.nodes[name].spec.serializeToDOM ?? schema.nodes[name].spec.toDOM;
|
|
842
|
-
if (toDOM) result.nodes[name] = toDOM;
|
|
843
|
-
}
|
|
844
|
-
result.nodes.text = (node) => document.createTextNode(node.text);
|
|
845
|
-
return result;
|
|
725
|
+
getDOMAttrs(node) {
|
|
726
|
+
if (!this.specs.length) return [];
|
|
727
|
+
return [this.getDOMAttrsProperties(node)];
|
|
846
728
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const serializedFragment = this.serializer.serializeFragment(parsedFragment);
|
|
850
|
-
const container = document.createDocumentFragment();
|
|
851
|
-
container.appendChild(serializedFragment);
|
|
852
|
-
options?.modifyDom?.(container);
|
|
853
|
-
const output = document.createElement("div");
|
|
854
|
-
output.appendChild(container);
|
|
855
|
-
return output.innerHTML;
|
|
729
|
+
extractFromNode(node) {
|
|
730
|
+
return Object.assign({}, ...Object.keys(this.attrs).map((attr) => ({ [attr]: node.attrs[attr] })));
|
|
856
731
|
}
|
|
857
732
|
};
|
|
858
733
|
//#endregion
|
|
859
|
-
//#region src/lib/rich-text-editor/rte/
|
|
860
|
-
var
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
node.check();
|
|
864
|
-
return node;
|
|
865
|
-
};
|
|
866
|
-
var RteInstance = class {
|
|
867
|
-
constructor(config, options) {
|
|
868
|
-
this.options = options;
|
|
869
|
-
this.feature = (Feature, featureId) => {
|
|
870
|
-
return this[require_slottable_request.impl].getPublicInterface(Feature, featureId);
|
|
871
|
-
};
|
|
872
|
-
this[require_slottable_request.impl] = new RteInstanceImpl(this, config, options);
|
|
734
|
+
//#region src/lib/rich-text-editor/rte/utils/textblock-marks.ts
|
|
735
|
+
var TextblockMarks = class {
|
|
736
|
+
constructor(specs) {
|
|
737
|
+
this.specs = specs;
|
|
873
738
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
*/
|
|
877
|
-
getDocument() {
|
|
878
|
-
return this[require_slottable_request.impl].state.doc.toJSON();
|
|
739
|
+
getAllowedMarksForNode(nodeName) {
|
|
740
|
+
return this.specs.filter((spec) => !spec.onNodeName || spec.onNodeName === nodeName).map((spec) => spec.markName);
|
|
879
741
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
*/
|
|
883
|
-
reset(initialDocument) {
|
|
884
|
-
this[require_slottable_request.impl].reset(initialDocument);
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Replaces the current selection with the given content.
|
|
888
|
-
* If no text is selected, this inserts the content at the cursor position.
|
|
889
|
-
*/
|
|
890
|
-
replaceSelection(content, options) {
|
|
891
|
-
const { state, tr, schema, dispatchTransaction } = this[require_slottable_request.impl];
|
|
892
|
-
tr.replaceSelection(new prosemirror_model.Slice(prosemirror_model.Fragment.fromJSON(schema, content), 0, 0));
|
|
893
|
-
tr.doc.check();
|
|
894
|
-
const $from = tr.doc.resolve(tr.mapping.map(state.selection.from));
|
|
895
|
-
const $to = tr.doc.resolve(tr.selection.to);
|
|
896
|
-
const [$head, $anchor] = options?.cursorPlacement === "start" ? [$from, $to] : [$to, $from];
|
|
897
|
-
if (options?.selectContent) tr.setSelection(state.selection instanceof prosemirror_state.AllSelection ? new prosemirror_state.AllSelection(tr.doc) : prosemirror_state.TextSelection.between($anchor, $head));
|
|
898
|
-
else tr.setSelection(prosemirror_state.TextSelection.between($head, $head));
|
|
899
|
-
dispatchTransaction(tr);
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* Replaces the entire document with the given new document.
|
|
903
|
-
* Unlike reset, this preserves the rest of the editor state. The undo history is preserved, so the user can undo the replacement.
|
|
904
|
-
*/
|
|
905
|
-
replaceDocument(newDocument, options) {
|
|
906
|
-
const { state, tr, schema, dispatchTransaction } = this[require_slottable_request.impl];
|
|
907
|
-
tr.replaceWith(0, state.doc.content.size, parseDocument(schema, newDocument));
|
|
908
|
-
if (options?.selectContent) tr.setSelection(new prosemirror_state.AllSelection(tr.doc));
|
|
909
|
-
else if (options?.cursorPlacement === "end") tr.setSelection(prosemirror_state.TextSelection.atEnd(tr.doc));
|
|
910
|
-
else tr.setSelection(prosemirror_state.TextSelection.atStart(tr.doc));
|
|
911
|
-
dispatchTransaction(tr);
|
|
742
|
+
getReferencedNodeNames() {
|
|
743
|
+
return new Set(this.specs.map((spec) => spec.onNodeName).filter(Boolean));
|
|
912
744
|
}
|
|
913
745
|
};
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region src/lib/rich-text-editor/rte/view.ts
|
|
748
|
+
/**
|
|
749
|
+
* Converts an RteDocument to an RteView tree for rendering outside the editor.
|
|
750
|
+
* The logic is adapted from ProseMirror's DOM serialization to ensure the resulting structure
|
|
751
|
+
* matches the editor's HTML structure.
|
|
752
|
+
*/
|
|
753
|
+
var convertToView = (doc, ctx) => {
|
|
754
|
+
const schema = ctx.config[require_slottable_request.impl].schema;
|
|
755
|
+
const getMarkRank = (mark) => schema.marks[mark.type].rank;
|
|
756
|
+
const marksEqual = (a, b) => {
|
|
757
|
+
if (a.type !== b.type) return false;
|
|
758
|
+
const attrsA = a.attrs;
|
|
759
|
+
const attrsB = b.attrs;
|
|
760
|
+
if (attrsA === attrsB) return true;
|
|
761
|
+
/* v8 ignore next -- not currently reachable since all attrs are required @preserve */
|
|
762
|
+
if (!attrsA || !attrsB) return false;
|
|
763
|
+
const keysA = Object.keys(attrsA);
|
|
764
|
+
const keysB = Object.keys(attrsB);
|
|
765
|
+
/* v8 ignore next -- not currently reachable since all attrs are required @preserve */
|
|
766
|
+
if (keysA.length !== keysB.length) return false;
|
|
767
|
+
for (const key of keysA) if (attrsA[key] !== attrsB[key]) return false;
|
|
768
|
+
return true;
|
|
769
|
+
};
|
|
770
|
+
const convertFragment = (nodes) => {
|
|
771
|
+
const result = [];
|
|
772
|
+
const active = [];
|
|
773
|
+
const activeContents = [result];
|
|
774
|
+
for (const node of nodes) {
|
|
775
|
+
const nodeMarks = [...node.marks ?? []].sort((a, b) => getMarkRank(a) - getMarkRank(b));
|
|
776
|
+
let keep = 0;
|
|
777
|
+
let rendered = 0;
|
|
778
|
+
while (keep < active.length && rendered < nodeMarks.length) {
|
|
779
|
+
if (!marksEqual(active[keep], nodeMarks[rendered])) break;
|
|
780
|
+
keep++;
|
|
781
|
+
rendered++;
|
|
782
|
+
}
|
|
783
|
+
while (active.length > keep) {
|
|
784
|
+
active.pop();
|
|
785
|
+
activeContents.pop();
|
|
786
|
+
}
|
|
787
|
+
while (rendered < nodeMarks.length) {
|
|
788
|
+
const mark = nodeMarks[rendered];
|
|
789
|
+
const markContent = [];
|
|
790
|
+
activeContents[activeContents.length - 1].push({
|
|
791
|
+
type: "mark",
|
|
792
|
+
mark,
|
|
793
|
+
children: {
|
|
794
|
+
type: "fragment",
|
|
795
|
+
content: markContent,
|
|
796
|
+
[require_slottable_request.impl]: ctx
|
|
797
|
+
},
|
|
798
|
+
[require_slottable_request.impl]: ctx
|
|
799
|
+
});
|
|
800
|
+
active.push(mark);
|
|
801
|
+
activeContents.push(markContent);
|
|
802
|
+
rendered++;
|
|
803
|
+
}
|
|
804
|
+
activeContents[activeContents.length - 1].push({
|
|
805
|
+
type: "node",
|
|
806
|
+
node,
|
|
807
|
+
children: convertFragment(node.content ?? []),
|
|
808
|
+
[require_slottable_request.impl]: ctx
|
|
809
|
+
});
|
|
928
810
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
this.options = options;
|
|
934
|
-
this.view = null;
|
|
935
|
-
this.dispatchTransaction = (tr) => {
|
|
936
|
-
const prevState = this.state;
|
|
937
|
-
this.state = this.state.apply(tr);
|
|
938
|
-
this.view?.updateState(this.state);
|
|
939
|
-
if (prevState.doc !== this.state.doc) this.options?.onChange?.();
|
|
940
|
-
return this.state;
|
|
811
|
+
return {
|
|
812
|
+
type: "fragment",
|
|
813
|
+
content: result,
|
|
814
|
+
[require_slottable_request.impl]: ctx
|
|
941
815
|
};
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
this.
|
|
955
|
-
doc: parseDocument(this.schema, initialDoc),
|
|
956
|
-
schema: this.config.schema,
|
|
957
|
-
plugins: require_slottable_request.sortedContributions(this.config.features.flatMap((feature) => feature.getPlugins(this)))
|
|
958
|
-
});
|
|
816
|
+
};
|
|
817
|
+
return {
|
|
818
|
+
type: "node",
|
|
819
|
+
node: doc,
|
|
820
|
+
children: convertFragment(doc.content),
|
|
821
|
+
[require_slottable_request.impl]: ctx
|
|
822
|
+
};
|
|
823
|
+
};
|
|
824
|
+
//#endregion
|
|
825
|
+
//#region src/lib/rich-text-editor/rte/config.ts
|
|
826
|
+
var RteConfig = class {
|
|
827
|
+
constructor(features) {
|
|
828
|
+
this[require_slottable_request.impl] = new RteConfigImpl(features);
|
|
959
829
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
this.initState(initialDocument);
|
|
963
|
-
this.updateHostState(currentHostState);
|
|
964
|
-
this.view?.updateState(this.state);
|
|
830
|
+
instantiateEditor(options) {
|
|
831
|
+
return new RteInstance(this, options);
|
|
965
832
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
}, {
|
|
971
|
-
state: this.state,
|
|
972
|
-
dispatchTransaction: this.dispatchTransaction
|
|
833
|
+
instantiateView(document, options) {
|
|
834
|
+
return convertToView(document, {
|
|
835
|
+
config: this,
|
|
836
|
+
options: { ...options }
|
|
973
837
|
});
|
|
974
838
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
839
|
+
};
|
|
840
|
+
var RteConfigImpl = class {
|
|
841
|
+
constructor(featuresFacades) {
|
|
842
|
+
const resolveFeatures = (features) => features.flatMap((f) => f.getFeatures().flatMap((subFeature) => subFeature === f ? f : resolveFeatures([subFeature])));
|
|
843
|
+
this.features = resolveFeatures(featuresFacades.map(require_slottable_request.getFeatureImpl));
|
|
844
|
+
this.featureMap = /* @__PURE__ */ new Map();
|
|
845
|
+
for (const f of this.features) {
|
|
846
|
+
if (this.featureMap.has(f.name)) throw new Error(`Duplicate feature: ${f.name}`);
|
|
847
|
+
this.featureMap.set(f.name, f);
|
|
979
848
|
}
|
|
849
|
+
this.featureFacadesMap = /* @__PURE__ */ new Map();
|
|
850
|
+
for (const facade of featuresFacades) {
|
|
851
|
+
const FacadeClass = facade.constructor;
|
|
852
|
+
const feature = require_slottable_request.getFeatureImpl(facade);
|
|
853
|
+
const instances = this.featureFacadesMap.get(FacadeClass);
|
|
854
|
+
if (instances) instances.push(feature);
|
|
855
|
+
else this.featureFacadesMap.set(FacadeClass, [feature]);
|
|
856
|
+
}
|
|
857
|
+
if (!this.featureMap.has("RteBase")) throw new Error("RteBase feature is required");
|
|
858
|
+
if (this.featureMap.has("RteLinkFeature") && !this.featureMap.has("RteToolbarFeature")) throw new Error("RteToolbarFeature is required for RteLinkFeature");
|
|
859
|
+
this.textblockAttrs = new TextblockAttrs(require_slottable_request.sortedContributions(this.features.flatMap((f) => f.getTextblockAttrs())));
|
|
860
|
+
this.textblockMarks = new TextblockMarks(require_slottable_request.sortedContributions(this.features.flatMap((f) => f.getTextblockMarks())));
|
|
861
|
+
const schemaContributions = require_slottable_request.sortedContributions(this.features.flatMap((f) => f.getSchema(this.textblockAttrs, this.textblockMarks)));
|
|
862
|
+
const schemaSpec = {
|
|
863
|
+
nodes: {},
|
|
864
|
+
marks: {}
|
|
865
|
+
};
|
|
866
|
+
for (const schema of schemaContributions) {
|
|
867
|
+
Object.assign(schemaSpec.nodes, schema.nodes ?? {});
|
|
868
|
+
Object.assign(schemaSpec.marks, schema.marks ?? {});
|
|
869
|
+
}
|
|
870
|
+
for (const referencedNodeName of this.textblockMarks.getReferencedNodeNames()) if (!(referencedNodeName in schemaSpec.nodes)) throw new Error(`Unknown node "${referencedNodeName}"`);
|
|
871
|
+
this.schema = new prosemirror_model.Schema(schemaSpec);
|
|
980
872
|
}
|
|
981
|
-
|
|
982
|
-
|
|
873
|
+
};
|
|
874
|
+
//#endregion
|
|
875
|
+
//#region src/lib/rich-text-editor/rte/utils/ui.ts
|
|
876
|
+
var isPropBinding = (prop) => typeof prop === "function";
|
|
877
|
+
var on = (event, prop, handler) => [
|
|
878
|
+
event,
|
|
879
|
+
prop,
|
|
880
|
+
handler
|
|
881
|
+
];
|
|
882
|
+
var UiCtx = class {
|
|
883
|
+
constructor(view, rte, props) {
|
|
884
|
+
this.view = view;
|
|
885
|
+
this.rte = rte;
|
|
886
|
+
this.props = props;
|
|
887
|
+
this.bindings = [];
|
|
983
888
|
}
|
|
984
|
-
|
|
985
|
-
return
|
|
889
|
+
evalProp(prop) {
|
|
890
|
+
return isPropBinding(prop) ? prop(this) : prop;
|
|
986
891
|
}
|
|
987
|
-
|
|
988
|
-
return
|
|
892
|
+
bindProp(prop, bindFn) {
|
|
893
|
+
if (prop === void 0) return;
|
|
894
|
+
else if (isPropBinding(prop)) {
|
|
895
|
+
const binding = () => bindFn(prop(this));
|
|
896
|
+
this.bindings.push(binding);
|
|
897
|
+
binding();
|
|
898
|
+
} else bindFn(prop);
|
|
989
899
|
}
|
|
990
|
-
|
|
991
|
-
const
|
|
992
|
-
if (!state) throw new Error("No host state available");
|
|
993
|
-
return state;
|
|
900
|
+
updateBindings() {
|
|
901
|
+
for (const binding of this.bindings) binding();
|
|
994
902
|
}
|
|
995
|
-
|
|
996
|
-
this.
|
|
903
|
+
shouldReturnFocusToEditor() {
|
|
904
|
+
return this.evalProp(this.props.shouldReturnFocusToEditor);
|
|
905
|
+
}
|
|
906
|
+
bindToEl(target, props = {}, events = [], children = []) {
|
|
907
|
+
for (const name in props) this.bindProp(props[name], (value) => {
|
|
908
|
+
target[name] = value;
|
|
909
|
+
});
|
|
910
|
+
for (const [name, value, bindFn] of events) if (value) target.addEventListener(name, bindFn(value));
|
|
911
|
+
for (const child of children) target.appendChild(child);
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
var createDiv = (ctx, props) => {
|
|
915
|
+
const div = document.createElement("div");
|
|
916
|
+
ctx.bindToEl(div, {
|
|
917
|
+
className: props.className,
|
|
918
|
+
slot: props.slot
|
|
919
|
+
}, [], props.children);
|
|
920
|
+
return div;
|
|
921
|
+
};
|
|
922
|
+
var createAnchor = (ctx, props) => {
|
|
923
|
+
const anchor = document.createElement("a");
|
|
924
|
+
ctx.bindToEl(anchor, {
|
|
925
|
+
href: props.href,
|
|
926
|
+
target: props.target,
|
|
927
|
+
rel: props.rel,
|
|
928
|
+
className: props.className
|
|
929
|
+
}, [], props.children);
|
|
930
|
+
return anchor;
|
|
931
|
+
};
|
|
932
|
+
var wrapperTargets = /* @__PURE__ */ new WeakMap();
|
|
933
|
+
var createOptionalTooltip = (ctx, props) => {
|
|
934
|
+
const tooltip = ctx.rte.createComponent(require_definition$6.Tooltip);
|
|
935
|
+
tooltip.setAttribute("exportparts", "vvd-theme-alternate");
|
|
936
|
+
ctx.bindToEl(tooltip, {
|
|
937
|
+
className: "ui-tooltip",
|
|
938
|
+
text: props.label,
|
|
939
|
+
placement: ctx.props.popupPlacement
|
|
940
|
+
});
|
|
941
|
+
ctx.bindProp(props.enabled, (enabled) => {
|
|
942
|
+
if (!enabled) tooltip.open = false;
|
|
943
|
+
tooltip.anchor = enabled ? props.anchor : void 0;
|
|
944
|
+
});
|
|
945
|
+
const wrapper = createDiv(ctx, {
|
|
946
|
+
className: "ui-tooltip-wrapper",
|
|
947
|
+
slot: props.slot,
|
|
948
|
+
children: [props.anchor, tooltip]
|
|
949
|
+
});
|
|
950
|
+
wrapperTargets.set(wrapper, props.anchor);
|
|
951
|
+
return wrapper;
|
|
952
|
+
};
|
|
953
|
+
var createButton = (ctx, props) => {
|
|
954
|
+
const variant = () => ctx.evalProp(props.variant) ?? "toolbar";
|
|
955
|
+
const size = () => variant() === "toolbar" ? "super-condensed" : "condensed";
|
|
956
|
+
const appearanceInactive = () => variant() === "popover-primary" ? "outlined" : "ghost-light";
|
|
957
|
+
const appearanceActive = () => variant() === "toolbar-menu" || variant() === "popover" ? "filled" : appearanceInactive();
|
|
958
|
+
const appearance = () => ctx.evalProp(props.active) ? appearanceActive() : appearanceInactive();
|
|
959
|
+
const connotation = () => ctx.evalProp(props.connotation) ?? (variant() === "toolbar-menu" && ctx.evalProp(props.active) ? "cta" : void 0);
|
|
960
|
+
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
|
|
961
|
+
const button = ctx.rte.createComponent(require_definition$1.Button);
|
|
962
|
+
ctx.bindToEl(button, {
|
|
963
|
+
size,
|
|
964
|
+
appearance,
|
|
965
|
+
disabled,
|
|
966
|
+
icon: props.icon,
|
|
967
|
+
autofocus: props.autofocus,
|
|
968
|
+
connotation,
|
|
969
|
+
[props.icon ? "ariaLabel" : "label"]: props.label,
|
|
970
|
+
pressed: () => Boolean(ctx.evalProp(props.active)),
|
|
971
|
+
ariaPressed: props.active !== void 0 ? () => ctx.evalProp(props.active) ? "true" : "false" : void 0
|
|
972
|
+
}, [on("click", props.onClick, (onClick) => () => {
|
|
973
|
+
if (!onClick() && ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
974
|
+
})]);
|
|
975
|
+
return createOptionalTooltip(ctx, {
|
|
976
|
+
enabled: () => Boolean(ctx.evalProp(props.icon) && !ctx.evalProp(props.noTooltip) && !disabled()),
|
|
977
|
+
label: props.label,
|
|
978
|
+
anchor: button,
|
|
979
|
+
slot: props.slot
|
|
980
|
+
});
|
|
981
|
+
};
|
|
982
|
+
var createMenu = (ctx, props) => {
|
|
983
|
+
const menu = ctx.rte.createComponent(require_definition$4.Menu);
|
|
984
|
+
ctx.bindToEl(menu, {
|
|
985
|
+
className: "ui-menu",
|
|
986
|
+
autoDismiss: true,
|
|
987
|
+
ariaLabel: props.label,
|
|
988
|
+
anchor: wrapperTargets.get(props.trigger) ?? props.trigger,
|
|
989
|
+
placement: ctx.props.popupPlacement,
|
|
990
|
+
offset: () => ctx.evalProp(ctx.props.menuOffset) ?? null
|
|
991
|
+
}, [], props.children);
|
|
992
|
+
const fragment = document.createDocumentFragment();
|
|
993
|
+
fragment.appendChild(props.trigger);
|
|
994
|
+
fragment.appendChild(menu);
|
|
995
|
+
return fragment;
|
|
996
|
+
};
|
|
997
|
+
var createMenuItem = (ctx, props) => {
|
|
998
|
+
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
|
|
999
|
+
const item = ctx.rte.createComponent(require_definition$3.MenuItem);
|
|
1000
|
+
ctx.bindToEl(item, {
|
|
1001
|
+
text: props.text,
|
|
1002
|
+
checked: props.checked,
|
|
1003
|
+
disabled,
|
|
1004
|
+
controlType: "radio",
|
|
1005
|
+
checkedAppearance: "tick-only"
|
|
1006
|
+
}, [on("change", props.onSelect, (onSelect) => () => {
|
|
1007
|
+
if (item.checked && !item.disabled) {
|
|
1008
|
+
if (ctx.evalProp(props.checked) !== item.checked) {
|
|
1009
|
+
onSelect();
|
|
1010
|
+
if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
})]);
|
|
1014
|
+
return item;
|
|
1015
|
+
};
|
|
1016
|
+
var createButtonGroup = (ctx, props) => createDiv(ctx, {
|
|
1017
|
+
slot: props.slot,
|
|
1018
|
+
className: "ui-button-group",
|
|
1019
|
+
children: props.children
|
|
1020
|
+
});
|
|
1021
|
+
function markActive(state, type) {
|
|
1022
|
+
const { from, $from, to, empty } = state.selection;
|
|
1023
|
+
if (empty) return !!type.isInSet(state.storedMarks || $from.marks());
|
|
1024
|
+
else return state.doc.rangeHasMark(from, to, type);
|
|
1025
|
+
}
|
|
1026
|
+
var createMarkToggle = (ctx, props) => createButton(ctx, {
|
|
1027
|
+
label: props.label,
|
|
1028
|
+
icon: props.icon,
|
|
1029
|
+
active: () => markActive(ctx.view.state, props.markType),
|
|
1030
|
+
disabled: () => !(0, prosemirror_commands.toggleMark)(props.markType)(ctx.view.state),
|
|
1031
|
+
onClick: () => {
|
|
1032
|
+
(0, prosemirror_commands.toggleMark)(props.markType)(ctx.view.state, ctx.view.dispatch);
|
|
997
1033
|
}
|
|
1034
|
+
});
|
|
1035
|
+
var createOption = (ctx, props) => {
|
|
1036
|
+
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
|
|
1037
|
+
const option = ctx.rte.createComponent(require_definition$7.ListboxOption);
|
|
1038
|
+
ctx.bindToEl(option, {
|
|
1039
|
+
value: props.value,
|
|
1040
|
+
text: props.text,
|
|
1041
|
+
disabled
|
|
1042
|
+
});
|
|
1043
|
+
return option;
|
|
1044
|
+
};
|
|
1045
|
+
var createSelect = (ctx, props) => {
|
|
1046
|
+
const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled));
|
|
1047
|
+
const select = ctx.rte.createComponent(require_definition$9.Select);
|
|
1048
|
+
select.setAttribute("data-class", "ui-select");
|
|
1049
|
+
ctx.bindToEl(select, {
|
|
1050
|
+
placeholder: " ",
|
|
1051
|
+
ariaLabel: props.label,
|
|
1052
|
+
appearance: "ghost",
|
|
1053
|
+
disabled
|
|
1054
|
+
}, [on("change", props.onSelect, (onSelect) => () => {
|
|
1055
|
+
const value = select.value;
|
|
1056
|
+
if (value) {
|
|
1057
|
+
onSelect(value);
|
|
1058
|
+
if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
1059
|
+
}
|
|
1060
|
+
})], props.children);
|
|
1061
|
+
queueMicrotask(() => {
|
|
1062
|
+
ctx.bindProp(props.value, (value) => select.value = value);
|
|
1063
|
+
});
|
|
1064
|
+
let hideTooltip = false;
|
|
1065
|
+
select.addEventListener("vwc-popup:open", () => {
|
|
1066
|
+
hideTooltip = true;
|
|
1067
|
+
ctx.updateBindings();
|
|
1068
|
+
});
|
|
1069
|
+
select.addEventListener("vwc-popup:close", () => {
|
|
1070
|
+
hideTooltip = false;
|
|
1071
|
+
ctx.updateBindings();
|
|
1072
|
+
});
|
|
1073
|
+
return createOptionalTooltip(ctx, {
|
|
1074
|
+
enabled: () => !hideTooltip && !disabled(),
|
|
1075
|
+
label: props.label,
|
|
1076
|
+
anchor: select
|
|
1077
|
+
});
|
|
1078
|
+
};
|
|
1079
|
+
var createDivider = (ctx) => {
|
|
1080
|
+
const divider = ctx.rte.createComponent(require_divider.Divider);
|
|
1081
|
+
ctx.bindToEl(divider, {
|
|
1082
|
+
className: "ui-divider",
|
|
1083
|
+
orientation: "vertical"
|
|
1084
|
+
});
|
|
1085
|
+
return divider;
|
|
998
1086
|
};
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
getDOMAttrsProperties(node) {
|
|
1014
|
-
if (!this.specs.length) return {};
|
|
1015
|
-
return { style: this.getStyle(node) };
|
|
1016
|
-
}
|
|
1017
|
-
getDOMAttrs(node) {
|
|
1018
|
-
if (!this.specs.length) return [];
|
|
1019
|
-
return [this.getDOMAttrsProperties(node)];
|
|
1020
|
-
}
|
|
1021
|
-
extractFromNode(node) {
|
|
1022
|
-
return Object.assign({}, ...Object.keys(this.attrs).map((attr) => ({ [attr]: node.attrs[attr] })));
|
|
1023
|
-
}
|
|
1087
|
+
var createTextField = (ctx, props) => {
|
|
1088
|
+
const textField = ctx.rte.createComponent(require_definition$5.TextField);
|
|
1089
|
+
ctx.bindToEl(textField, {
|
|
1090
|
+
label: props.label,
|
|
1091
|
+
value: props.value,
|
|
1092
|
+
placeholder: props.placeholder,
|
|
1093
|
+
slot: props.slot,
|
|
1094
|
+
autofocus: props.autofocus,
|
|
1095
|
+
type: props.type,
|
|
1096
|
+
helperText: props.helperText
|
|
1097
|
+
}, [on("input", props.onInput, (onInput) => () => {
|
|
1098
|
+
onInput(textField.value);
|
|
1099
|
+
})]);
|
|
1100
|
+
return textField;
|
|
1024
1101
|
};
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
this.specs = specs;
|
|
1030
|
-
}
|
|
1031
|
-
getAllowedMarksForNode(nodeName) {
|
|
1032
|
-
return this.specs.filter((spec) => !spec.onNodeName || spec.onNodeName === nodeName).map((spec) => spec.markName);
|
|
1033
|
-
}
|
|
1034
|
-
getReferencedNodeNames() {
|
|
1035
|
-
return new Set(this.specs.map((spec) => spec.onNodeName).filter(Boolean));
|
|
1036
|
-
}
|
|
1102
|
+
var createText = (ctx, props) => {
|
|
1103
|
+
const textNode = document.createTextNode("");
|
|
1104
|
+
ctx.bindToEl(textNode, { textContent: props.text });
|
|
1105
|
+
return textNode;
|
|
1037
1106
|
};
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
const
|
|
1049
|
-
if (
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
const result = [];
|
|
1064
|
-
const active = [];
|
|
1065
|
-
const activeContents = [result];
|
|
1066
|
-
for (const node of nodes) {
|
|
1067
|
-
const nodeMarks = [...node.marks ?? []].sort((a, b) => getMarkRank(a) - getMarkRank(b));
|
|
1068
|
-
let keep = 0;
|
|
1069
|
-
let rendered = 0;
|
|
1070
|
-
while (keep < active.length && rendered < nodeMarks.length) {
|
|
1071
|
-
if (!marksEqual(active[keep], nodeMarks[rendered])) break;
|
|
1072
|
-
keep++;
|
|
1073
|
-
rendered++;
|
|
1074
|
-
}
|
|
1075
|
-
while (active.length > keep) {
|
|
1076
|
-
active.pop();
|
|
1077
|
-
activeContents.pop();
|
|
1078
|
-
}
|
|
1079
|
-
while (rendered < nodeMarks.length) {
|
|
1080
|
-
const mark = nodeMarks[rendered];
|
|
1081
|
-
const markContent = [];
|
|
1082
|
-
activeContents[activeContents.length - 1].push({
|
|
1083
|
-
type: "mark",
|
|
1084
|
-
mark,
|
|
1085
|
-
children: {
|
|
1086
|
-
type: "fragment",
|
|
1087
|
-
content: markContent,
|
|
1088
|
-
[require_slottable_request.impl]: ctx
|
|
1089
|
-
},
|
|
1090
|
-
[require_slottable_request.impl]: ctx
|
|
1091
|
-
});
|
|
1092
|
-
active.push(mark);
|
|
1093
|
-
activeContents.push(markContent);
|
|
1094
|
-
rendered++;
|
|
1095
|
-
}
|
|
1096
|
-
activeContents[activeContents.length - 1].push({
|
|
1097
|
-
type: "node",
|
|
1098
|
-
node,
|
|
1099
|
-
children: convertFragment(node.content ?? []),
|
|
1100
|
-
[require_slottable_request.impl]: ctx
|
|
1107
|
+
var createSingleSlot = (ctx, props) => {
|
|
1108
|
+
const slot = document.createElement("slot");
|
|
1109
|
+
slot.name = props.name;
|
|
1110
|
+
let currentEl = null;
|
|
1111
|
+
const listeners = [];
|
|
1112
|
+
function cleanup() {
|
|
1113
|
+
for (const { el, type, handler } of listeners) el.removeEventListener(type, handler);
|
|
1114
|
+
listeners.length = 0;
|
|
1115
|
+
currentEl = null;
|
|
1116
|
+
}
|
|
1117
|
+
for (const [key, prop] of Object.entries(props.assignedProps)) ctx.bindProp(prop, (value) => {
|
|
1118
|
+
if (currentEl) currentEl[key] = value;
|
|
1119
|
+
});
|
|
1120
|
+
function applyPropsAndEvents(el) {
|
|
1121
|
+
for (const [key, prop] of Object.entries(props.assignedProps)) el[key] = ctx.evalProp(prop);
|
|
1122
|
+
for (const [type, handler] of Object.entries(props.assignedEvents)) {
|
|
1123
|
+
const listener = (e) => {
|
|
1124
|
+
handler(e);
|
|
1125
|
+
if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
|
|
1126
|
+
};
|
|
1127
|
+
el.addEventListener(type, listener);
|
|
1128
|
+
listeners.push({
|
|
1129
|
+
el,
|
|
1130
|
+
type,
|
|
1131
|
+
handler: listener
|
|
1101
1132
|
});
|
|
1102
1133
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
children: convertFragment(doc.content),
|
|
1113
|
-
[require_slottable_request.impl]: ctx
|
|
1134
|
+
}
|
|
1135
|
+
const processSlot = () => {
|
|
1136
|
+
const first = slot.assignedElements({ flatten: true })[0];
|
|
1137
|
+
if (first === currentEl) return;
|
|
1138
|
+
cleanup();
|
|
1139
|
+
if (first) {
|
|
1140
|
+
currentEl = first;
|
|
1141
|
+
applyPropsAndEvents(first);
|
|
1142
|
+
}
|
|
1114
1143
|
};
|
|
1144
|
+
slot.addEventListener("slotchange", processSlot);
|
|
1145
|
+
queueMicrotask(processSlot);
|
|
1146
|
+
return slot;
|
|
1115
1147
|
};
|
|
1116
1148
|
//#endregion
|
|
1117
|
-
//#region src/lib/rich-text-editor/rte/
|
|
1118
|
-
var
|
|
1119
|
-
constructor(
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
return new RteInstance(this, options);
|
|
1149
|
+
//#region src/lib/rich-text-editor/rte/features/internal/history.ts
|
|
1150
|
+
var RteHistoryFeatureImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
1151
|
+
constructor(config) {
|
|
1152
|
+
super();
|
|
1153
|
+
this.config = config;
|
|
1154
|
+
this.name = "RteHistoryFeature";
|
|
1124
1155
|
}
|
|
1125
|
-
|
|
1126
|
-
return
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1156
|
+
getPlugins() {
|
|
1157
|
+
return [this.contribution((0, prosemirror_history.history)()), this.contribution((0, prosemirror_keymap.keymap)({
|
|
1158
|
+
"Mod-z": prosemirror_history.undo,
|
|
1159
|
+
"Ctrl-y": prosemirror_history.redo,
|
|
1160
|
+
"Cmd-Z": prosemirror_history.redo
|
|
1161
|
+
}))];
|
|
1130
1162
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
marks: {}
|
|
1157
|
-
};
|
|
1158
|
-
for (const schema of schemaContributions) {
|
|
1159
|
-
Object.assign(schemaSpec.nodes, schema.nodes ?? {});
|
|
1160
|
-
Object.assign(schemaSpec.marks, schema.marks ?? {});
|
|
1161
|
-
}
|
|
1162
|
-
for (const referencedNodeName of this.textblockMarks.getReferencedNodeNames()) if (!(referencedNodeName in schemaSpec.nodes)) throw new Error(`Unknown node "${referencedNodeName}"`);
|
|
1163
|
-
this.schema = new prosemirror_model.Schema(schemaSpec);
|
|
1163
|
+
getToolbarItems() {
|
|
1164
|
+
if (!this.config.showToolbarButtons) return [];
|
|
1165
|
+
return [this.contribution({
|
|
1166
|
+
section: "history",
|
|
1167
|
+
render: (ctx) => createButton(ctx, {
|
|
1168
|
+
label: (ctx) => ctx.rte.getLocale().richTextEditor.undo,
|
|
1169
|
+
icon: "undo-line",
|
|
1170
|
+
disabled: (ctx) => !(0, prosemirror_history.undo)(ctx.view.state),
|
|
1171
|
+
onClick: () => {
|
|
1172
|
+
const { state, dispatch } = ctx.view;
|
|
1173
|
+
(0, prosemirror_history.undo)(state, dispatch);
|
|
1174
|
+
}
|
|
1175
|
+
})
|
|
1176
|
+
}, 1), this.contribution({
|
|
1177
|
+
section: "history",
|
|
1178
|
+
render: (ctx) => createButton(ctx, {
|
|
1179
|
+
label: (ctx) => ctx.rte.getLocale().richTextEditor.redo,
|
|
1180
|
+
icon: "redo-line",
|
|
1181
|
+
disabled: (ctx) => !(0, prosemirror_history.redo)(ctx.view.state),
|
|
1182
|
+
onClick: () => {
|
|
1183
|
+
const { state, dispatch } = ctx.view;
|
|
1184
|
+
(0, prosemirror_history.redo)(state, dispatch);
|
|
1185
|
+
}
|
|
1186
|
+
})
|
|
1187
|
+
}, 2)];
|
|
1164
1188
|
}
|
|
1165
1189
|
};
|
|
1166
1190
|
//#endregion
|
|
@@ -1346,6 +1370,7 @@ var RteBaseImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
|
1346
1370
|
return [
|
|
1347
1371
|
this,
|
|
1348
1372
|
new RteCoreImpl(),
|
|
1373
|
+
new RteHistoryFeatureImpl({ showToolbarButtons: this.config?.historyToolbarButtons ?? true }),
|
|
1349
1374
|
new RteBasicTextBlocksImpl({
|
|
1350
1375
|
heading1: this.config?.heading1 ?? false,
|
|
1351
1376
|
heading2: this.config?.heading2 ?? false,
|
|
@@ -1363,6 +1388,20 @@ var RteBaseImpl = class extends require_slottable_request.RteFeatureImpl {
|
|
|
1363
1388
|
},
|
|
1364
1389
|
set disabled(value) {
|
|
1365
1390
|
core.disabled.setValue(rte, value);
|
|
1391
|
+
},
|
|
1392
|
+
get scrollThreshold() {
|
|
1393
|
+
return core.scrollThreshold;
|
|
1394
|
+
},
|
|
1395
|
+
set scrollThreshold(value) {
|
|
1396
|
+
core.scrollThreshold = value;
|
|
1397
|
+
rte.view?.setProps({ scrollThreshold: value });
|
|
1398
|
+
},
|
|
1399
|
+
get scrollMargin() {
|
|
1400
|
+
return core.scrollMargin;
|
|
1401
|
+
},
|
|
1402
|
+
set scrollMargin(value) {
|
|
1403
|
+
core.scrollMargin = value;
|
|
1404
|
+
rte.view?.setProps({ scrollMargin: value });
|
|
1366
1405
|
}
|
|
1367
1406
|
};
|
|
1368
1407
|
}
|
|
@@ -1953,7 +1992,7 @@ var RteTextColorPickerFeatureImpl = class extends require_slottable_request.RteF
|
|
|
1953
1992
|
if (selectionColor === null) selectionColor = observedColor ?? null;
|
|
1954
1993
|
else if (observedColor !== selectionColor) selectionColor = mixedColor;
|
|
1955
1994
|
};
|
|
1956
|
-
state.doc.nodesBetween(from, to, (node,
|
|
1995
|
+
state.doc.nodesBetween(from, to, (node, _pos, parent) => {
|
|
1957
1996
|
if (selectionColor === mixedColor) return false;
|
|
1958
1997
|
if (!node.isLeaf) {
|
|
1959
1998
|
if (node.type.allowsMarkType(textColor) && node.childCount === 0) observeColor(this.defaultColorForNode?.[node.type.name]);
|
|
@@ -2702,7 +2741,7 @@ var InlineImageView = class {
|
|
|
2702
2741
|
this.img.className = "inline-image";
|
|
2703
2742
|
this.update(node);
|
|
2704
2743
|
this.img.addEventListener("load", () => {
|
|
2705
|
-
const pos = this.getPos
|
|
2744
|
+
const pos = this.getPos();
|
|
2706
2745
|
if (pos) {
|
|
2707
2746
|
const { state, dispatch } = this.view;
|
|
2708
2747
|
const currentNode = state.doc.nodeAt(pos);
|
|
@@ -2809,6 +2848,7 @@ var RteInlineImageFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
2809
2848
|
shouldReturnFocusToEditor: true
|
|
2810
2849
|
});
|
|
2811
2850
|
popover = rte.createComponent(Popover);
|
|
2851
|
+
popover.kind = "imageOptions";
|
|
2812
2852
|
popover.offset = 4;
|
|
2813
2853
|
const content = createDiv(ctx, {
|
|
2814
2854
|
className: "inline-image-popover",
|
|
@@ -2869,7 +2909,7 @@ var RteInlineImageFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
2869
2909
|
} }))];
|
|
2870
2910
|
}
|
|
2871
2911
|
calculateSmallWidth(naturalWidth) {
|
|
2872
|
-
return Math.min(300, naturalWidth / 2)
|
|
2912
|
+
return `${Math.min(300, naturalWidth / 2)}px`;
|
|
2873
2913
|
}
|
|
2874
2914
|
getSelectedInlineImage(state) {
|
|
2875
2915
|
const sel = state.selection;
|
|
@@ -3002,13 +3042,13 @@ var RteFileHandlerFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
3002
3042
|
if (resolved.type === "error") console.error("Error in handleFiles handler:", resolved.error);
|
|
3003
3043
|
};
|
|
3004
3044
|
return [this.contribution(insertPointPlaceholderPlugin), this.contribution(new prosemirror_state.Plugin({ props: {
|
|
3005
|
-
handlePaste: (
|
|
3045
|
+
handlePaste: (_view, event) => {
|
|
3006
3046
|
const files = Array.from(event.clipboardData.files);
|
|
3007
3047
|
if (!files.length) return false;
|
|
3008
3048
|
handleFiles(files, { type: "selection" });
|
|
3009
3049
|
return true;
|
|
3010
3050
|
},
|
|
3011
|
-
handleDrop: (view, event
|
|
3051
|
+
handleDrop: (view, event) => {
|
|
3012
3052
|
const files = Array.from(event.dataTransfer.files);
|
|
3013
3053
|
if (!files.length) return false;
|
|
3014
3054
|
let target = view.posAtCoords({
|
|
@@ -3037,7 +3077,7 @@ var RteDropHandlerFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
3037
3077
|
this.config = config;
|
|
3038
3078
|
this.name = "RteDebugFeature";
|
|
3039
3079
|
}
|
|
3040
|
-
getPlugins(
|
|
3080
|
+
getPlugins() {
|
|
3041
3081
|
const dragOverResults = /* @__PURE__ */ new WeakMap();
|
|
3042
3082
|
let lastResult = false;
|
|
3043
3083
|
const onDragOver = (event) => {
|
|
@@ -3075,7 +3115,7 @@ var RteDropHandlerFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
3075
3115
|
viewport.removeEventListener("dragleave", onDragLeave);
|
|
3076
3116
|
} };
|
|
3077
3117
|
} })), this.contribution(new prosemirror_state.Plugin({ props: { handleDOMEvents: {
|
|
3078
|
-
dragover: (
|
|
3118
|
+
dragover: (_view, event) => {
|
|
3079
3119
|
const result = this.config.onViewportDragOver?.(event) ?? false;
|
|
3080
3120
|
dragOverResults.set(event, result);
|
|
3081
3121
|
lastResult = result;
|
|
@@ -3086,7 +3126,7 @@ var RteDropHandlerFeatureImpl = class extends require_slottable_request.RteFeatu
|
|
|
3086
3126
|
}
|
|
3087
3127
|
return false;
|
|
3088
3128
|
},
|
|
3089
|
-
drop: (
|
|
3129
|
+
drop: () => {
|
|
3090
3130
|
return lastResult;
|
|
3091
3131
|
}
|
|
3092
3132
|
} } }), require_slottable_request.contributionPriority.high)];
|
|
@@ -3225,7 +3265,6 @@ var RteInputRuleFeature = require_slottable_request.featureFacade(RteInputRuleFe
|
|
|
3225
3265
|
//#endregion
|
|
3226
3266
|
//#region src/lib/rich-text-editor/rte/features/keyboard-shortcuts.ts
|
|
3227
3267
|
function toCommand(handler, rteInstance) {
|
|
3228
|
-
if (handler.length === 0) return (_state, _dispatch) => handler();
|
|
3229
3268
|
return (_state, _dispatch) => handler(rteInstance);
|
|
3230
3269
|
}
|
|
3231
3270
|
var RteKeyboardShortcutsFeatureImpl = class extends require_slottable_request.RteFeatureImpl {
|