@fastkit/vui 0.7.59 → 0.7.65
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/dist/tool/index.js +1 -0
- package/dist/tool/vite-plugin.d.ts.map +1 -1
- package/dist/vui.cjs.js +616 -39
- package/dist/vui.cjs.prod.js +616 -39
- package/dist/vui.css +219 -0
- package/dist/vui.d.ts +141 -4
- package/dist/vui.min.css +1 -1
- package/dist/vui.min.css.map +1 -1
- package/dist/vui.mjs +606 -39
- package/package.json +7 -6
- package/src/components/VButton/VButtonGroup.scss +4 -0
- package/src/components/VButton/VButtonGroup.tsx +12 -1
- package/src/components/VWysiwygEditor/.DS_Store +0 -0
- package/src/components/VWysiwygEditor/VWysiwygEditor.scss +4 -0
- package/src/components/VWysiwygEditor/VWysiwygEditor.tsx +65 -22
- package/src/components/VWysiwygEditor/extensions/.DS_Store +0 -0
- package/src/components/VWysiwygEditor/extensions/color.ts +72 -0
- package/src/components/VWysiwygEditor/extensions/index.ts +2 -0
- package/src/components/VWysiwygEditor/extensions/linter/.DS_Store +0 -0
- package/src/components/VWysiwygEditor/extensions/linter/Linter.scss +140 -0
- package/src/components/VWysiwygEditor/extensions/linter/Linter.tsx +214 -0
- package/src/components/VWysiwygEditor/extensions/linter/LinterPlugin.ts +65 -0
- package/src/components/VWysiwygEditor/extensions/linter/index.ts +5 -0
- package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.tsx +50 -0
- package/src/components/VWysiwygEditor/extensions/linter/plugins/HeadingLevel.ts +39 -0
- package/src/components/VWysiwygEditor/extensions/linter/plugins/Punctuation.ts +49 -0
- package/src/components/VWysiwygEditor/extensions/linter/plugins/index.ts +3 -0
- package/src/components/VWysiwygEditor/extensions/linter/utils.ts +28 -0
- package/src/components/VWysiwygEditor/index.ts +1 -0
- package/src/components/VWysiwygEditor/schemes.ts +190 -4
- package/src/components/VWysiwygEditor/tools/color.scss +140 -0
- package/src/components/VWysiwygEditor/tools/color.tsx +90 -0
- package/src/components/VWysiwygEditor/tools/index.ts +1 -1
- package/src/service.tsx +5 -0
- package/src/tool/vite-plugin.ts +1 -0
- package/src/components/VWysiwygEditor/tools/text-color.ts +0 -14
package/dist/vui.cjs.js
CHANGED
|
@@ -15,6 +15,9 @@ var vueAppLayout = require('@fastkit/vue-app-layout');
|
|
|
15
15
|
var vueFormControl = require('@fastkit/vue-form-control');
|
|
16
16
|
var vue3 = require('@tiptap/vue-3');
|
|
17
17
|
var StarterKit = require('@tiptap/starter-kit');
|
|
18
|
+
var core = require('@tiptap/core');
|
|
19
|
+
var prosemirrorView = require('prosemirror-view');
|
|
20
|
+
var prosemirrorState = require('prosemirror-state');
|
|
18
21
|
var extensionBulletList = require('@tiptap/extension-bullet-list');
|
|
19
22
|
var extensionBold = require('@tiptap/extension-bold');
|
|
20
23
|
var extensionItalic = require('@tiptap/extension-italic');
|
|
@@ -23,10 +26,12 @@ var extensionHistory = require('@tiptap/extension-history');
|
|
|
23
26
|
var extensionLink = require('@tiptap/extension-link');
|
|
24
27
|
var rules = require('@fastkit/rules');
|
|
25
28
|
var extensionOrderedList = require('@tiptap/extension-ordered-list');
|
|
29
|
+
var TextStyle = require('@tiptap/extension-text-style');
|
|
26
30
|
|
|
27
31
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
28
32
|
|
|
29
33
|
var StarterKit__default = /*#__PURE__*/_interopDefaultLegacy(StarterKit);
|
|
34
|
+
var TextStyle__default = /*#__PURE__*/_interopDefaultLegacy(TextStyle);
|
|
30
35
|
|
|
31
36
|
const CONTROL_SIZES = ['sm', 'md', 'lg'];
|
|
32
37
|
const CONTROL_FIELD_VARIANTS = ['outlined', 'filled', 'flat'];
|
|
@@ -1229,6 +1234,7 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1229
1234
|
|
|
1230
1235
|
setup(props, ctx) {
|
|
1231
1236
|
return () => {
|
|
1237
|
+
let hasIcon = false;
|
|
1232
1238
|
let buttonLength = 0;
|
|
1233
1239
|
let tmp = vueUtils.renderSlotOrEmpty(ctx.slots) || [];
|
|
1234
1240
|
|
|
@@ -1245,6 +1251,11 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1245
1251
|
}
|
|
1246
1252
|
|
|
1247
1253
|
buttonLength++;
|
|
1254
|
+
|
|
1255
|
+
if (!hasIcon && node.props && !!node.props.icon) {
|
|
1256
|
+
hasIcon = true;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1248
1259
|
return {
|
|
1249
1260
|
isButton: true,
|
|
1250
1261
|
node
|
|
@@ -1261,6 +1272,7 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1261
1272
|
...childProps,
|
|
1262
1273
|
rouded: false,
|
|
1263
1274
|
class: ['v-button-group__item', {
|
|
1275
|
+
'v-button--icon': hasIcon,
|
|
1264
1276
|
'v-button-group__item--has-left': hasLeft,
|
|
1265
1277
|
'v-button-group__item--has-right': hasRight
|
|
1266
1278
|
}]
|
|
@@ -1270,7 +1282,9 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1270
1282
|
return child.node;
|
|
1271
1283
|
});
|
|
1272
1284
|
return vue.createVNode("div", {
|
|
1273
|
-
"class":
|
|
1285
|
+
"class": ['v-button-group', {
|
|
1286
|
+
'v-button-group--has-icon': hasIcon
|
|
1287
|
+
}]
|
|
1274
1288
|
}, [$children]);
|
|
1275
1289
|
};
|
|
1276
1290
|
}
|
|
@@ -2874,13 +2888,105 @@ const VTextarea = vue.defineComponent({
|
|
|
2874
2888
|
|
|
2875
2889
|
});
|
|
2876
2890
|
|
|
2891
|
+
const EDITOR_EVENTS = [
|
|
2892
|
+
'beforeCreate',
|
|
2893
|
+
'create',
|
|
2894
|
+
'update',
|
|
2895
|
+
'selectionUpdate',
|
|
2896
|
+
'transaction',
|
|
2897
|
+
'focus',
|
|
2898
|
+
'blur',
|
|
2899
|
+
'destroy',
|
|
2900
|
+
];
|
|
2901
|
+
const prefixedEventName = (source) => {
|
|
2902
|
+
return `on${source.charAt(0).toUpperCase()}${source.slice(1)}`;
|
|
2903
|
+
};
|
|
2904
|
+
class WysiwygEditorInitializeContext {
|
|
2905
|
+
listeners = {};
|
|
2906
|
+
_vui;
|
|
2907
|
+
get vui() {
|
|
2908
|
+
return this._vui();
|
|
2909
|
+
}
|
|
2910
|
+
constructor(vuiGetter, opts = {}) {
|
|
2911
|
+
this._vui = vuiGetter;
|
|
2912
|
+
EDITOR_EVENTS.forEach((event) => {
|
|
2913
|
+
this.listeners[event] = [];
|
|
2914
|
+
const prefixed = prefixedEventName(event);
|
|
2915
|
+
const fn = opts[prefixed];
|
|
2916
|
+
fn && this.listeners[event].push(fn);
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2919
|
+
on(ev, handler) {
|
|
2920
|
+
this.listeners[ev].push(handler);
|
|
2921
|
+
return () => this.off(ev, handler);
|
|
2922
|
+
}
|
|
2923
|
+
off(ev, handler) {
|
|
2924
|
+
this.listeners[ev] = this.listeners[ev].filter((_handler) => _handler !== handler);
|
|
2925
|
+
}
|
|
2926
|
+
editorOptions() {
|
|
2927
|
+
const opts = {};
|
|
2928
|
+
EDITOR_EVENTS.forEach((event) => {
|
|
2929
|
+
const prefixed = prefixedEventName(event);
|
|
2930
|
+
opts[prefixed] = (props) => {
|
|
2931
|
+
const handlers = this.listeners[event];
|
|
2932
|
+
handlers.forEach((handler) => {
|
|
2933
|
+
handler(props);
|
|
2934
|
+
});
|
|
2935
|
+
};
|
|
2936
|
+
});
|
|
2937
|
+
return opts;
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2941
|
+
// extension: Extension<Options, Storage>,
|
|
2942
|
+
// ): Extension<Options, Storage>;
|
|
2943
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2944
|
+
// node: Node<Options, Storage>,
|
|
2945
|
+
// ): Node<Options, Storage>;
|
|
2946
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2947
|
+
// mark: Mark<Options, Storage>,
|
|
2948
|
+
// ): Mark<Options, Storage>;
|
|
2949
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2950
|
+
// factory: WysiwygExtensionFactory<Options, Storage>,
|
|
2951
|
+
// ): WysiwygExtensionFactory<Options, Storage>;
|
|
2952
|
+
function isCreatedWysiwygExtension(source) {
|
|
2953
|
+
return (!!source &&
|
|
2954
|
+
typeof source === 'object' &&
|
|
2955
|
+
source.__isCreatedWysiwygExtension === true);
|
|
2956
|
+
}
|
|
2957
|
+
function createWysiwygExtension(extension) {
|
|
2958
|
+
const ext = {
|
|
2959
|
+
__isCreatedWysiwygExtension: true,
|
|
2960
|
+
_configs: [],
|
|
2961
|
+
configure: (opts) => {
|
|
2962
|
+
opts && ext._configs.push(opts);
|
|
2963
|
+
return ext;
|
|
2964
|
+
},
|
|
2965
|
+
raw: extension,
|
|
2966
|
+
};
|
|
2967
|
+
return ext;
|
|
2968
|
+
}
|
|
2969
|
+
function resolveRawWysiwygExtension(raw, ctx) {
|
|
2970
|
+
if (isCreatedWysiwygExtension(raw)) {
|
|
2971
|
+
const { raw: _raw, _configs } = raw;
|
|
2972
|
+
let ext = typeof _raw === 'function' ? _raw(ctx) : _raw;
|
|
2973
|
+
_configs.forEach((config) => {
|
|
2974
|
+
ext = ext.configure(config);
|
|
2975
|
+
});
|
|
2976
|
+
return ext;
|
|
2977
|
+
}
|
|
2978
|
+
return typeof raw === 'function' ? raw(ctx) : raw;
|
|
2979
|
+
}
|
|
2980
|
+
function resolveRawWysiwygExtensions(raws, ctx) {
|
|
2981
|
+
return raws.map((raw) => resolveRawWysiwygExtension(raw, ctx));
|
|
2982
|
+
}
|
|
2877
2983
|
function resolveRawWysiwygEditorTool(raw, vui) {
|
|
2878
2984
|
return typeof raw === 'function' ? raw(vui) : raw;
|
|
2879
2985
|
}
|
|
2880
|
-
function resolveRawWysiwygEditorTools(
|
|
2986
|
+
function resolveRawWysiwygEditorTools(rawTools, vui) {
|
|
2881
2987
|
const tools = [];
|
|
2882
2988
|
const extensions = [];
|
|
2883
|
-
|
|
2989
|
+
rawTools.forEach((raw) => {
|
|
2884
2990
|
let resolved = resolveRawWysiwygEditorTool(raw, vui);
|
|
2885
2991
|
if (!Array.isArray(resolved)) {
|
|
2886
2992
|
resolved = [resolved];
|
|
@@ -2911,6 +3017,10 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
2911
3017
|
...createControlFieldProviderProps(),
|
|
2912
3018
|
...createControlProps(),
|
|
2913
3019
|
...vueKit.defineSlotsProps(),
|
|
3020
|
+
extensions: {
|
|
3021
|
+
type: Array,
|
|
3022
|
+
default: () => []
|
|
3023
|
+
},
|
|
2914
3024
|
tools: {
|
|
2915
3025
|
type: Array,
|
|
2916
3026
|
default: () => []
|
|
@@ -2933,13 +3043,40 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
2933
3043
|
nodeType: VUI_WYSIWYG_EDITOR_SYMBOL,
|
|
2934
3044
|
validationValue: () => textRef.value
|
|
2935
3045
|
});
|
|
3046
|
+
const initializeCtx = new WysiwygEditorInitializeContext(() => vui, {
|
|
3047
|
+
onCreate: ({
|
|
3048
|
+
editor
|
|
3049
|
+
}) => {
|
|
3050
|
+
textRef.value = editor.getText();
|
|
3051
|
+
updateEditable();
|
|
3052
|
+
},
|
|
3053
|
+
onFocus: ({
|
|
3054
|
+
event
|
|
3055
|
+
}) => {
|
|
3056
|
+
inputControl.focusHandler(event);
|
|
3057
|
+
},
|
|
3058
|
+
onBlur: ({
|
|
3059
|
+
event
|
|
3060
|
+
}) => {
|
|
3061
|
+
inputControl.blurHandler(event);
|
|
3062
|
+
},
|
|
3063
|
+
onUpdate: ({
|
|
3064
|
+
editor
|
|
3065
|
+
}) => {
|
|
3066
|
+
inputControl.value = editor.getHTML();
|
|
3067
|
+
textRef.value = editor.getText();
|
|
3068
|
+
}
|
|
3069
|
+
});
|
|
2936
3070
|
const extensions = [StarterKit__default.configure({
|
|
2937
3071
|
bold: false,
|
|
2938
3072
|
bulletList: false,
|
|
2939
3073
|
orderedList: false,
|
|
2940
3074
|
history: false,
|
|
2941
3075
|
italic: false
|
|
2942
|
-
}),
|
|
3076
|
+
}), // Linter.configure({
|
|
3077
|
+
// plugins: [BadWords(['abc', 'evidently']), Punctuation, HeadingLevel],
|
|
3078
|
+
// }),
|
|
3079
|
+
...resolveRawWysiwygExtensions(props.extensions, initializeCtx), ...wysiwygSettings.value.extensions];
|
|
2943
3080
|
|
|
2944
3081
|
const updateEditable = () => {
|
|
2945
3082
|
if (!editor.value) return;
|
|
@@ -2953,23 +3090,13 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
2953
3090
|
$editor.commands.setContent(modelValue == null ? '' : modelValue, false);
|
|
2954
3091
|
textRef.value = $editor.getText();
|
|
2955
3092
|
});
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
onFocus: ctx => {
|
|
2964
|
-
inputControl.focusHandler(ctx.event);
|
|
2965
|
-
},
|
|
2966
|
-
onBlur: ctx => {
|
|
2967
|
-
inputControl.blurHandler(ctx.event);
|
|
2968
|
-
},
|
|
2969
|
-
onUpdate: ev => {
|
|
2970
|
-
inputControl.value = ev.editor.getHTML();
|
|
2971
|
-
textRef.value = ev.editor.getText();
|
|
2972
|
-
},
|
|
3093
|
+
initializeCtx.on('create', ({
|
|
3094
|
+
editor
|
|
3095
|
+
}) => {
|
|
3096
|
+
textRef.value = editor.getText();
|
|
3097
|
+
updateEditable();
|
|
3098
|
+
});
|
|
3099
|
+
const editor = vue3.useEditor({ ...initializeCtx.editorOptions(),
|
|
2973
3100
|
autofocus: props.autofocus,
|
|
2974
3101
|
content: props.modelValue,
|
|
2975
3102
|
extensions,
|
|
@@ -3015,9 +3142,9 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3015
3142
|
const _editor = editor.value;
|
|
3016
3143
|
const variant = vui.setting(bubbleMenu ? 'containedVariant' : 'plainVariant');
|
|
3017
3144
|
return vue.createVNode(VButtonGroup, {
|
|
3018
|
-
"class": {
|
|
3145
|
+
"class": ['v-wysiwyg-editor__toolbar', {
|
|
3019
3146
|
'v-wysiwyg-editor__floating-toolbar': props.floatingToolbar
|
|
3020
|
-
},
|
|
3147
|
+
}],
|
|
3021
3148
|
"variant": variant
|
|
3022
3149
|
}, _isSlot$7(_slot = tools.map(({
|
|
3023
3150
|
key,
|
|
@@ -3029,16 +3156,23 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3029
3156
|
const isActive = !!_editor && resolveContextableValue(context, active);
|
|
3030
3157
|
const isDisabled = !inputControl.canOperation || !!_editor && resolveContextableValue(context, disabled);
|
|
3031
3158
|
let iconName;
|
|
3159
|
+
let child;
|
|
3032
3160
|
|
|
3033
3161
|
if (typeof icon === 'function') {
|
|
3034
3162
|
if (_editor) {
|
|
3035
|
-
|
|
3163
|
+
const _child = icon(context);
|
|
3164
|
+
|
|
3165
|
+
if (typeof _child === 'function') {
|
|
3166
|
+
child = _child();
|
|
3167
|
+
} else {
|
|
3168
|
+
iconName = child;
|
|
3169
|
+
}
|
|
3036
3170
|
}
|
|
3037
3171
|
} else {
|
|
3038
3172
|
iconName = icon;
|
|
3039
3173
|
}
|
|
3040
3174
|
|
|
3041
|
-
if (!iconName) return;
|
|
3175
|
+
if (!iconName && child == null) return;
|
|
3042
3176
|
return vue.createVNode(VButton, {
|
|
3043
3177
|
"tabindex": -1,
|
|
3044
3178
|
"key": key,
|
|
@@ -3046,12 +3180,17 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3046
3180
|
"onClick": ev => onClick(context, ev),
|
|
3047
3181
|
"color": isActive ? toolButtonActiveColor : undefined,
|
|
3048
3182
|
"disabled": isDisabled
|
|
3049
|
-
},
|
|
3183
|
+
}, _isSlot$7(child) ? child : {
|
|
3184
|
+
default: () => [child]
|
|
3185
|
+
});
|
|
3050
3186
|
})) ? _slot : {
|
|
3051
3187
|
default: () => [_slot]
|
|
3052
3188
|
});
|
|
3053
3189
|
};
|
|
3054
3190
|
|
|
3191
|
+
vue.onBeforeUnmount(() => {
|
|
3192
|
+
editor.value && editor.value.destroy();
|
|
3193
|
+
});
|
|
3055
3194
|
return {
|
|
3056
3195
|
editor,
|
|
3057
3196
|
...inputControl.expose(),
|
|
@@ -3127,6 +3266,376 @@ function resolveContextableValue(ctx, source) {
|
|
|
3127
3266
|
return typeof source === 'function' ? source(ctx) : source;
|
|
3128
3267
|
}
|
|
3129
3268
|
|
|
3269
|
+
const PROBLEM_CLASS_NAME = 'v-linter__problem';
|
|
3270
|
+
const ISSUE_ICON_CLASS_NAME = 'v-linter__issue-icon';
|
|
3271
|
+
const ISSUE_DATASET_NAME = 'data-issue-id';
|
|
3272
|
+
|
|
3273
|
+
function resolveWysiwygLinterFixMessage(message) {
|
|
3274
|
+
return typeof message === 'function' ? message() : message;
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3277
|
+
function renderIcon(view, issue) {
|
|
3278
|
+
const {
|
|
3279
|
+
level = 'warning'
|
|
3280
|
+
} = issue;
|
|
3281
|
+
const icon = document.createElement('div');
|
|
3282
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3283
|
+
icon.className = `${ISSUE_ICON_CLASS_NAME} ${level}-scope`;
|
|
3284
|
+
icon.setAttribute(ISSUE_DATASET_NAME, issue.id);
|
|
3285
|
+
|
|
3286
|
+
if (typeof message === 'string') {
|
|
3287
|
+
icon.title = message;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
return icon;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
function runAllLinterPlugins(doc, plugins) {
|
|
3294
|
+
const decorations = [];
|
|
3295
|
+
const issues = plugins.map(RegisteredLinterPlugin => {
|
|
3296
|
+
return new RegisteredLinterPlugin(doc).scan().getResults();
|
|
3297
|
+
}).flat();
|
|
3298
|
+
issues.forEach(issue => {
|
|
3299
|
+
const {
|
|
3300
|
+
level = 'warning',
|
|
3301
|
+
icon
|
|
3302
|
+
} = issue;
|
|
3303
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3304
|
+
decorations.push(prosemirrorView.Decoration.inline(issue.from, issue.to, {
|
|
3305
|
+
class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
|
|
3306
|
+
'data-issue-id': issue.id,
|
|
3307
|
+
title: typeof message === 'string' ? message : undefined
|
|
3308
|
+
}));
|
|
3309
|
+
|
|
3310
|
+
if (icon) {
|
|
3311
|
+
decorations.push(prosemirrorView.Decoration.widget(issue.from, view => renderIcon(view, issue)));
|
|
3312
|
+
}
|
|
3313
|
+
});
|
|
3314
|
+
const decorationSet = prosemirrorView.DecorationSet.create(doc, decorations);
|
|
3315
|
+
return {
|
|
3316
|
+
issues,
|
|
3317
|
+
decorationSet
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
const WysiwygLinter = createWysiwygExtension(ctx => {
|
|
3322
|
+
function showMenu(view, issue, event) {
|
|
3323
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3324
|
+
const variant = ctx.vui.setting('containedVariant');
|
|
3325
|
+
const scope = ctx.vui.setting(`${issue.level}Scope`);
|
|
3326
|
+
return ctx.vui.menu({
|
|
3327
|
+
activator: event,
|
|
3328
|
+
content: stack => vue.createVNode("div", {
|
|
3329
|
+
"class": "v-linter__issue-menu__body"
|
|
3330
|
+
}, [vue.createVNode("div", {
|
|
3331
|
+
"class": ['v-linter__issue-menu__message', `${scope}-scope ${variant}`]
|
|
3332
|
+
}, [message]), issue.fix.length && vue.createVNode("div", {
|
|
3333
|
+
"class": "v-linter__issue-menu__fixers"
|
|
3334
|
+
}, [issue.fix.map((fixer, index) => vue.createVNode("div", {
|
|
3335
|
+
"key": index,
|
|
3336
|
+
"class": "v-linter__issue-menu__fixer"
|
|
3337
|
+
}, [vue.createVNode("button", {
|
|
3338
|
+
"type": "button",
|
|
3339
|
+
"class": "v-linter__issue-menu__fixer__button",
|
|
3340
|
+
"onClick": () => {
|
|
3341
|
+
stack.close();
|
|
3342
|
+
fixer.handler(view, issue);
|
|
3343
|
+
}
|
|
3344
|
+
}, [vue.createVNode("span", {
|
|
3345
|
+
"class": "v-linter__issue-menu__fixer__button__message"
|
|
3346
|
+
}, [resolveWysiwygLinterFixMessage(fixer.message)])])]))])])
|
|
3347
|
+
});
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
return core.Extension.create({
|
|
3351
|
+
name: 'linter',
|
|
3352
|
+
|
|
3353
|
+
addOptions() {
|
|
3354
|
+
return {
|
|
3355
|
+
plugins: []
|
|
3356
|
+
};
|
|
3357
|
+
},
|
|
3358
|
+
|
|
3359
|
+
addStorage() {
|
|
3360
|
+
return {
|
|
3361
|
+
issues: []
|
|
3362
|
+
};
|
|
3363
|
+
},
|
|
3364
|
+
|
|
3365
|
+
addProseMirrorPlugins() {
|
|
3366
|
+
const {
|
|
3367
|
+
plugins
|
|
3368
|
+
} = this.options;
|
|
3369
|
+
const {
|
|
3370
|
+
storage
|
|
3371
|
+
} = this;
|
|
3372
|
+
|
|
3373
|
+
const runAll = doc => {
|
|
3374
|
+
const {
|
|
3375
|
+
issues,
|
|
3376
|
+
decorationSet
|
|
3377
|
+
} = runAllLinterPlugins(doc, plugins);
|
|
3378
|
+
storage.issues = issues;
|
|
3379
|
+
return decorationSet;
|
|
3380
|
+
};
|
|
3381
|
+
|
|
3382
|
+
const getIssue = id => storage.issues.find(issue => issue.id === id);
|
|
3383
|
+
|
|
3384
|
+
const getIssueElementByEvent = source => {
|
|
3385
|
+
if (!source || !(source instanceof HTMLElement)) {
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
const issueId = source.getAttribute(ISSUE_DATASET_NAME);
|
|
3390
|
+
const issue = issueId && getIssue(issueId);
|
|
3391
|
+
if (!issue) return;
|
|
3392
|
+
return {
|
|
3393
|
+
issue
|
|
3394
|
+
};
|
|
3395
|
+
};
|
|
3396
|
+
|
|
3397
|
+
return [new prosemirrorState.Plugin({
|
|
3398
|
+
key: new prosemirrorState.PluginKey('linter'),
|
|
3399
|
+
state: {
|
|
3400
|
+
init(_, {
|
|
3401
|
+
doc
|
|
3402
|
+
}) {
|
|
3403
|
+
return runAll(doc);
|
|
3404
|
+
},
|
|
3405
|
+
|
|
3406
|
+
apply(transaction, oldState) {
|
|
3407
|
+
return transaction.docChanged ? runAll(transaction.doc) : oldState;
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
},
|
|
3411
|
+
props: {
|
|
3412
|
+
decorations(state) {
|
|
3413
|
+
return this.getState(state);
|
|
3414
|
+
},
|
|
3415
|
+
|
|
3416
|
+
handleClick(view, _, event) {
|
|
3417
|
+
const info = getIssueElementByEvent(event.target);
|
|
3418
|
+
|
|
3419
|
+
if (!info) {
|
|
3420
|
+
return false;
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
const {
|
|
3424
|
+
issue
|
|
3425
|
+
} = info;
|
|
3426
|
+
const {
|
|
3427
|
+
from,
|
|
3428
|
+
to
|
|
3429
|
+
} = issue;
|
|
3430
|
+
|
|
3431
|
+
const focus = () => view.dispatch(view.state.tr.setSelection(prosemirrorState.TextSelection.create(view.state.doc, from, to)).scrollIntoView());
|
|
3432
|
+
|
|
3433
|
+
focus();
|
|
3434
|
+
showMenu(view, issue, event);
|
|
3435
|
+
return true;
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3438
|
+
}
|
|
3439
|
+
})];
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
});
|
|
3443
|
+
});
|
|
3444
|
+
|
|
3445
|
+
let IDX = 256, BUFFER;
|
|
3446
|
+
const HEX = [];
|
|
3447
|
+
while (IDX--)
|
|
3448
|
+
HEX[IDX] = (IDX + 256).toString(16).substring(1);
|
|
3449
|
+
function cheepUUID() {
|
|
3450
|
+
let i = 0, num, out = '';
|
|
3451
|
+
if (!BUFFER || IDX + 16 > 256) {
|
|
3452
|
+
BUFFER = Array((i = 256));
|
|
3453
|
+
while (i--)
|
|
3454
|
+
BUFFER[i] = (256 * Math.random()) | 0;
|
|
3455
|
+
i = IDX = 0;
|
|
3456
|
+
}
|
|
3457
|
+
for (; i < 16; i++) {
|
|
3458
|
+
num = BUFFER[IDX + i];
|
|
3459
|
+
if (i == 6)
|
|
3460
|
+
out += HEX[(num & 15) | 64];
|
|
3461
|
+
else if (i == 8)
|
|
3462
|
+
out += HEX[(num & 63) | 128];
|
|
3463
|
+
else
|
|
3464
|
+
out += HEX[num];
|
|
3465
|
+
if (i & 1 && i > 1 && i < 11)
|
|
3466
|
+
out += '-';
|
|
3467
|
+
}
|
|
3468
|
+
IDX++;
|
|
3469
|
+
return out;
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
class WysiwygLinterPlugin {
|
|
3473
|
+
doc;
|
|
3474
|
+
results = [];
|
|
3475
|
+
constructor(doc) {
|
|
3476
|
+
this.doc = doc;
|
|
3477
|
+
}
|
|
3478
|
+
record(result) {
|
|
3479
|
+
const { fix = [], icon = false } = result;
|
|
3480
|
+
this.results.push({
|
|
3481
|
+
level: 'error',
|
|
3482
|
+
id: cheepUUID(),
|
|
3483
|
+
...result,
|
|
3484
|
+
fix: Array.isArray(fix) ? fix : [fix],
|
|
3485
|
+
icon,
|
|
3486
|
+
});
|
|
3487
|
+
}
|
|
3488
|
+
scan() {
|
|
3489
|
+
return this;
|
|
3490
|
+
}
|
|
3491
|
+
getResults() {
|
|
3492
|
+
return this.results;
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
function WysiwygLinterBadWords(words) {
|
|
3497
|
+
const regex = new RegExp(`\\b(${words.join('|')})\\b`);
|
|
3498
|
+
return class WysiwygLinterBadWords extends WysiwygLinterPlugin {
|
|
3499
|
+
scan() {
|
|
3500
|
+
this.doc.descendants((node, position) => {
|
|
3501
|
+
if (!node.isText) {
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
const matches = regex.exec(node.text);
|
|
3506
|
+
|
|
3507
|
+
if (matches) {
|
|
3508
|
+
const fixValue = matches[0] + '!!!!!';
|
|
3509
|
+
this.record({
|
|
3510
|
+
level: 'warning',
|
|
3511
|
+
message: `Try not to say '${matches[0]}'`,
|
|
3512
|
+
from: position + matches.index,
|
|
3513
|
+
to: position + matches.index + matches[0].length,
|
|
3514
|
+
fix: [{
|
|
3515
|
+
message: () => vue.createVNode("span", null, [vue.createVNode("code", null, [fixValue]), vue.createTextVNode("\u306B\u4FEE\u6B63\u3059\u308B\u3002")]),
|
|
3516
|
+
handler: () => {
|
|
3517
|
+
console.log('hoge');
|
|
3518
|
+
}
|
|
3519
|
+
}, {
|
|
3520
|
+
message: 'どうにかする',
|
|
3521
|
+
handler: () => {
|
|
3522
|
+
console.log('hoge');
|
|
3523
|
+
}
|
|
3524
|
+
}]
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
});
|
|
3528
|
+
return this;
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
class WysiwygLinterHeadingLevel extends WysiwygLinterPlugin {
|
|
3535
|
+
fixHeader(level) {
|
|
3536
|
+
return function ({ state, dispatch }, issue) {
|
|
3537
|
+
dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level }));
|
|
3538
|
+
};
|
|
3539
|
+
}
|
|
3540
|
+
scan() {
|
|
3541
|
+
let lastHeadLevel = null;
|
|
3542
|
+
this.doc.descendants((node, position) => {
|
|
3543
|
+
if (node.type.name === 'heading') {
|
|
3544
|
+
// Check whether heading levels fit under the current level
|
|
3545
|
+
const { level } = node.attrs;
|
|
3546
|
+
if (lastHeadLevel != null && level > lastHeadLevel + 1) {
|
|
3547
|
+
this.record({
|
|
3548
|
+
message: `Heading too small (${level} under ${lastHeadLevel})`,
|
|
3549
|
+
from: position + 1,
|
|
3550
|
+
to: position + 1 + node.content.size,
|
|
3551
|
+
fix: {
|
|
3552
|
+
message: '修正する',
|
|
3553
|
+
handler: this.fixHeader(lastHeadLevel + 1),
|
|
3554
|
+
},
|
|
3555
|
+
});
|
|
3556
|
+
}
|
|
3557
|
+
lastHeadLevel = level;
|
|
3558
|
+
}
|
|
3559
|
+
});
|
|
3560
|
+
return this;
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
class WysiwygLinterPunctuation extends WysiwygLinterPlugin {
|
|
3565
|
+
regex = / ([,.!?:]) ?/g;
|
|
3566
|
+
fix(replacement) {
|
|
3567
|
+
return function ({ state, dispatch }, issue) {
|
|
3568
|
+
dispatch(state.tr.replaceWith(issue.from, issue.to, state.schema.text(replacement)));
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
scan() {
|
|
3572
|
+
this.doc.descendants((node, position) => {
|
|
3573
|
+
if (!node.isText) {
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
if (!node.text) {
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
const matches = this.regex.exec(node.text);
|
|
3580
|
+
if (matches) {
|
|
3581
|
+
this.record({
|
|
3582
|
+
message: 'Suspicious spacing around punctuation',
|
|
3583
|
+
from: position + matches.index,
|
|
3584
|
+
to: position + matches.index + matches[0].length,
|
|
3585
|
+
fix: {
|
|
3586
|
+
message: 'Fix it!!!',
|
|
3587
|
+
handler: this.fix(`${matches[1]} `),
|
|
3588
|
+
},
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3591
|
+
});
|
|
3592
|
+
return this;
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
const WysiwygColorExtension = core.Extension.create({
|
|
3597
|
+
name: 'color',
|
|
3598
|
+
addOptions() {
|
|
3599
|
+
return {
|
|
3600
|
+
types: ['textStyle'],
|
|
3601
|
+
};
|
|
3602
|
+
},
|
|
3603
|
+
addGlobalAttributes() {
|
|
3604
|
+
return [
|
|
3605
|
+
{
|
|
3606
|
+
types: this.options.types,
|
|
3607
|
+
attributes: {
|
|
3608
|
+
color: {
|
|
3609
|
+
default: null,
|
|
3610
|
+
parseHTML: (element) => element.style.color.replace(/['"]+/g, ''),
|
|
3611
|
+
renderHTML: (attributes) => {
|
|
3612
|
+
if (!attributes.color) {
|
|
3613
|
+
return {};
|
|
3614
|
+
}
|
|
3615
|
+
return {
|
|
3616
|
+
style: `color: ${attributes.color}`,
|
|
3617
|
+
};
|
|
3618
|
+
},
|
|
3619
|
+
},
|
|
3620
|
+
},
|
|
3621
|
+
},
|
|
3622
|
+
];
|
|
3623
|
+
},
|
|
3624
|
+
addCommands() {
|
|
3625
|
+
return {
|
|
3626
|
+
setColor: (color) => ({ chain }) => {
|
|
3627
|
+
return chain().setMark('textStyle', { color }).run();
|
|
3628
|
+
},
|
|
3629
|
+
unsetColor: () => ({ chain }) => {
|
|
3630
|
+
return chain()
|
|
3631
|
+
.setMark('textStyle', { color: null })
|
|
3632
|
+
.removeEmptyTextStyle()
|
|
3633
|
+
.run();
|
|
3634
|
+
},
|
|
3635
|
+
};
|
|
3636
|
+
},
|
|
3637
|
+
});
|
|
3638
|
+
|
|
3130
3639
|
const WysiwygBulletListTool = (vui, options) => {
|
|
3131
3640
|
const tool = {
|
|
3132
3641
|
key: 'bulletList',
|
|
@@ -3267,18 +3776,73 @@ const WysiwygOrderedListTool = (vui, options) => {
|
|
|
3267
3776
|
return tool;
|
|
3268
3777
|
};
|
|
3269
3778
|
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
};
|
|
3779
|
+
function createWysiwygColorTool(opts) {
|
|
3780
|
+
const WysiwygColorTool = vui => {
|
|
3781
|
+
const tool = {
|
|
3782
|
+
key: 'textColor',
|
|
3783
|
+
// active: ({ editor }) => editor.isActive('textStyle'),
|
|
3784
|
+
icon: ({
|
|
3785
|
+
editor
|
|
3786
|
+
}) => () => {
|
|
3787
|
+
const color = editor.getAttributes('textStyle').color;
|
|
3788
|
+
const style = {
|
|
3789
|
+
color
|
|
3790
|
+
};
|
|
3791
|
+
return vue.createVNode("span", {
|
|
3792
|
+
"class": "v-wysiwyg-color-tool__button"
|
|
3793
|
+
}, [vue.createVNode(VIcon, {
|
|
3794
|
+
"class": "v-wysiwyg-color-tool__button__icon",
|
|
3795
|
+
"name": vui.icon('editorTextColor')
|
|
3796
|
+
}, null), vue.createVNode("span", {
|
|
3797
|
+
"class": "v-wysiwyg-color-tool__button__bar",
|
|
3798
|
+
"style": style
|
|
3799
|
+
}, null)]);
|
|
3800
|
+
},
|
|
3801
|
+
onClick: (ctx, ev) => {
|
|
3802
|
+
ctx.vui.menu({
|
|
3803
|
+
class: 'v-wysiwyg-color-tool__menu',
|
|
3804
|
+
activator: ev,
|
|
3805
|
+
content: stack => vue.createVNode("div", {
|
|
3806
|
+
"class": ['v-wysiwyg-color-tool__items', {
|
|
3807
|
+
'v-wysiwyg-color-tool__items--with-label': opts.withLabel
|
|
3808
|
+
}]
|
|
3809
|
+
}, [opts.items.map((item, index) => vue.createVNode("button", {
|
|
3810
|
+
"key": item.key == null ? index : item.key,
|
|
3811
|
+
"class": "v-wysiwyg-color-tool__item",
|
|
3812
|
+
"type": "button",
|
|
3813
|
+
"onClick": () => {
|
|
3814
|
+
const {
|
|
3815
|
+
color
|
|
3816
|
+
} = item;
|
|
3817
|
+
let command = ctx.editor.chain().focus();
|
|
3818
|
+
|
|
3819
|
+
if (color) {
|
|
3820
|
+
command = command.setColor(color);
|
|
3821
|
+
} else {
|
|
3822
|
+
command = command.unsetColor();
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
command.run();
|
|
3826
|
+
stack.close();
|
|
3827
|
+
}
|
|
3828
|
+
}, [vue.createVNode("span", {
|
|
3829
|
+
"class": "v-wysiwyg-color-tool__item__color",
|
|
3830
|
+
"style": item.color ? {
|
|
3831
|
+
color: item.color
|
|
3832
|
+
} : {}
|
|
3833
|
+
}, null), opts.withLabel && vue.createVNode("span", {
|
|
3834
|
+
"class": "v-wysiwyg-color-tool__item__name"
|
|
3835
|
+
}, [item.name])]))])
|
|
3836
|
+
});
|
|
3837
|
+
},
|
|
3838
|
+
floating: true,
|
|
3839
|
+
extensions: [TextStyle__default, WysiwygColorExtension]
|
|
3840
|
+
};
|
|
3841
|
+
return tool;
|
|
3842
|
+
};
|
|
3843
|
+
|
|
3844
|
+
return WysiwygColorTool;
|
|
3845
|
+
}
|
|
3282
3846
|
|
|
3283
3847
|
const {
|
|
3284
3848
|
props,
|
|
@@ -4895,6 +5459,10 @@ class VuiService {
|
|
|
4895
5459
|
return this.stack.snackbar(...args);
|
|
4896
5460
|
}
|
|
4897
5461
|
|
|
5462
|
+
menu(...args) {
|
|
5463
|
+
return this.stack.menu(...args);
|
|
5464
|
+
}
|
|
5465
|
+
|
|
4898
5466
|
formPrompt(settings, slot) {
|
|
4899
5467
|
let form;
|
|
4900
5468
|
const options = {
|
|
@@ -5119,13 +5687,19 @@ exports.VuiInjectionKey = VuiInjectionKey;
|
|
|
5119
5687
|
exports.VuiPlugin = VuiPlugin;
|
|
5120
5688
|
exports.VuiService = VuiService;
|
|
5121
5689
|
exports.WysiwygBulletListTool = WysiwygBulletListTool;
|
|
5690
|
+
exports.WysiwygColorExtension = WysiwygColorExtension;
|
|
5691
|
+
exports.WysiwygEditorInitializeContext = WysiwygEditorInitializeContext;
|
|
5122
5692
|
exports.WysiwygFormatBoldTool = WysiwygFormatBoldTool;
|
|
5123
5693
|
exports.WysiwygFormatItalicTool = WysiwygFormatItalicTool;
|
|
5124
5694
|
exports.WysiwygFormatUnderlineTool = WysiwygFormatUnderlineTool;
|
|
5125
5695
|
exports.WysiwygHistoryTool = WysiwygHistoryTool;
|
|
5126
5696
|
exports.WysiwygLinkTool = WysiwygLinkTool;
|
|
5697
|
+
exports.WysiwygLinter = WysiwygLinter;
|
|
5698
|
+
exports.WysiwygLinterBadWords = WysiwygLinterBadWords;
|
|
5699
|
+
exports.WysiwygLinterHeadingLevel = WysiwygLinterHeadingLevel;
|
|
5700
|
+
exports.WysiwygLinterPlugin = WysiwygLinterPlugin;
|
|
5701
|
+
exports.WysiwygLinterPunctuation = WysiwygLinterPunctuation;
|
|
5127
5702
|
exports.WysiwygOrderedListTool = WysiwygOrderedListTool;
|
|
5128
|
-
exports.WysiwygTextColorTool = WysiwygTextColorTool;
|
|
5129
5703
|
exports.configureDataTableDefaults = configureDataTableDefaults;
|
|
5130
5704
|
exports.createAvatarProps = createAvatarProps;
|
|
5131
5705
|
exports.createCardProps = createCardProps;
|
|
@@ -5139,6 +5713,8 @@ exports.createPaperBaseProps = createPaperBaseProps;
|
|
|
5139
5713
|
exports.createPaperProps = createPaperProps;
|
|
5140
5714
|
exports.createRequiredChipRenderer = createRequiredChipRenderer;
|
|
5141
5715
|
exports.createVFormProps = createVFormProps;
|
|
5716
|
+
exports.createWysiwygColorTool = createWysiwygColorTool;
|
|
5717
|
+
exports.createWysiwygExtension = createWysiwygExtension;
|
|
5142
5718
|
exports.defineFormSelectorComponent = defineFormSelectorComponent;
|
|
5143
5719
|
exports.iconProps = iconProps;
|
|
5144
5720
|
exports.installVuiPlugin = installVuiPlugin;
|
|
@@ -5153,6 +5729,7 @@ exports.renderNavigationItemInput = renderNavigationItemInput;
|
|
|
5153
5729
|
exports.resolveNavigationItemInput = resolveNavigationItemInput;
|
|
5154
5730
|
exports.resolveRawIconProp = resolveRawIconProp;
|
|
5155
5731
|
exports.resolveRawWysiwygEditorTools = resolveRawWysiwygEditorTools;
|
|
5732
|
+
exports.resolveRawWysiwygExtensions = resolveRawWysiwygExtensions;
|
|
5156
5733
|
exports.splitAttrs = splitAttrs;
|
|
5157
5734
|
exports.useControl = useControl;
|
|
5158
5735
|
exports.useControlField = useControlField;
|