@fastkit/vui 0.7.61 → 0.7.64
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 +437 -228
- package/dist/vui.cjs.prod.js +437 -228
- package/dist/vui.css +166 -12
- package/dist/vui.d.ts +101 -54
- package/dist/vui.min.css +1 -1
- package/dist/vui.min.css.map +1 -1
- package/dist/vui.mjs +431 -225
- 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/VWysiwygEditor.scss +4 -0
- package/src/components/VWysiwygEditor/VWysiwygEditor.tsx +19 -9
- 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 +1 -0
- package/src/components/VWysiwygEditor/extensions/linter/.DS_Store +0 -0
- package/src/components/VWysiwygEditor/extensions/linter/Linter.scss +80 -15
- package/src/components/VWysiwygEditor/extensions/linter/Linter.tsx +210 -0
- package/src/components/VWysiwygEditor/extensions/linter/LinterPlugin.ts +29 -11
- package/src/components/VWysiwygEditor/extensions/linter/index.ts +3 -3
- package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.tsx +50 -0
- package/src/components/VWysiwygEditor/extensions/linter/plugins/HeadingLevel.ts +9 -3
- package/src/components/VWysiwygEditor/extensions/linter/plugins/Punctuation.ts +9 -3
- package/src/components/VWysiwygEditor/extensions/linter/plugins/index.ts +3 -3
- package/src/components/VWysiwygEditor/extensions/linter/utils.ts +28 -0
- package/src/components/VWysiwygEditor/schemes.ts +87 -5
- 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/extensions/linter/Linter.ts +0 -262
- package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.ts +0 -34
- package/src/components/VWysiwygEditor/tools/text-color.ts +0 -14
package/dist/vui.cjs.js
CHANGED
|
@@ -26,10 +26,12 @@ var extensionHistory = require('@tiptap/extension-history');
|
|
|
26
26
|
var extensionLink = require('@tiptap/extension-link');
|
|
27
27
|
var rules = require('@fastkit/rules');
|
|
28
28
|
var extensionOrderedList = require('@tiptap/extension-ordered-list');
|
|
29
|
+
var TextStyle = require('@tiptap/extension-text-style');
|
|
29
30
|
|
|
30
31
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
31
32
|
|
|
32
33
|
var StarterKit__default = /*#__PURE__*/_interopDefaultLegacy(StarterKit);
|
|
34
|
+
var TextStyle__default = /*#__PURE__*/_interopDefaultLegacy(TextStyle);
|
|
33
35
|
|
|
34
36
|
const CONTROL_SIZES = ['sm', 'md', 'lg'];
|
|
35
37
|
const CONTROL_FIELD_VARIANTS = ['outlined', 'filled', 'flat'];
|
|
@@ -1232,6 +1234,7 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1232
1234
|
|
|
1233
1235
|
setup(props, ctx) {
|
|
1234
1236
|
return () => {
|
|
1237
|
+
let hasIcon = false;
|
|
1235
1238
|
let buttonLength = 0;
|
|
1236
1239
|
let tmp = vueUtils.renderSlotOrEmpty(ctx.slots) || [];
|
|
1237
1240
|
|
|
@@ -1248,6 +1251,11 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1248
1251
|
}
|
|
1249
1252
|
|
|
1250
1253
|
buttonLength++;
|
|
1254
|
+
|
|
1255
|
+
if (!hasIcon && node.props && !!node.props.icon) {
|
|
1256
|
+
hasIcon = true;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1251
1259
|
return {
|
|
1252
1260
|
isButton: true,
|
|
1253
1261
|
node
|
|
@@ -1264,6 +1272,7 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1264
1272
|
...childProps,
|
|
1265
1273
|
rouded: false,
|
|
1266
1274
|
class: ['v-button-group__item', {
|
|
1275
|
+
'v-button--icon': hasIcon,
|
|
1267
1276
|
'v-button-group__item--has-left': hasLeft,
|
|
1268
1277
|
'v-button-group__item--has-right': hasRight
|
|
1269
1278
|
}]
|
|
@@ -1273,7 +1282,9 @@ const VButtonGroup = vue.defineComponent({
|
|
|
1273
1282
|
return child.node;
|
|
1274
1283
|
});
|
|
1275
1284
|
return vue.createVNode("div", {
|
|
1276
|
-
"class":
|
|
1285
|
+
"class": ['v-button-group', {
|
|
1286
|
+
'v-button-group--has-icon': hasIcon
|
|
1287
|
+
}]
|
|
1277
1288
|
}, [$children]);
|
|
1278
1289
|
};
|
|
1279
1290
|
}
|
|
@@ -2892,7 +2903,12 @@ const prefixedEventName = (source) => {
|
|
|
2892
2903
|
};
|
|
2893
2904
|
class WysiwygEditorInitializeContext {
|
|
2894
2905
|
listeners = {};
|
|
2895
|
-
|
|
2906
|
+
_vui;
|
|
2907
|
+
get vui() {
|
|
2908
|
+
return this._vui();
|
|
2909
|
+
}
|
|
2910
|
+
constructor(vuiGetter, opts = {}) {
|
|
2911
|
+
this._vui = vuiGetter;
|
|
2896
2912
|
EDITOR_EVENTS.forEach((event) => {
|
|
2897
2913
|
this.listeners[event] = [];
|
|
2898
2914
|
const prefixed = prefixedEventName(event);
|
|
@@ -2921,7 +2937,44 @@ class WysiwygEditorInitializeContext {
|
|
|
2921
2937
|
return opts;
|
|
2922
2938
|
}
|
|
2923
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
|
+
}
|
|
2924
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
|
+
}
|
|
2925
2978
|
return typeof raw === 'function' ? raw(ctx) : raw;
|
|
2926
2979
|
}
|
|
2927
2980
|
function resolveRawWysiwygExtensions(raws, ctx) {
|
|
@@ -2990,7 +3043,7 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
2990
3043
|
nodeType: VUI_WYSIWYG_EDITOR_SYMBOL,
|
|
2991
3044
|
validationValue: () => textRef.value
|
|
2992
3045
|
});
|
|
2993
|
-
const initializeCtx = new WysiwygEditorInitializeContext({
|
|
3046
|
+
const initializeCtx = new WysiwygEditorInitializeContext(() => vui, {
|
|
2994
3047
|
onCreate: ({
|
|
2995
3048
|
editor
|
|
2996
3049
|
}) => {
|
|
@@ -3089,9 +3142,9 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3089
3142
|
const _editor = editor.value;
|
|
3090
3143
|
const variant = vui.setting(bubbleMenu ? 'containedVariant' : 'plainVariant');
|
|
3091
3144
|
return vue.createVNode(VButtonGroup, {
|
|
3092
|
-
"class": {
|
|
3145
|
+
"class": ['v-wysiwyg-editor__toolbar', {
|
|
3093
3146
|
'v-wysiwyg-editor__floating-toolbar': props.floatingToolbar
|
|
3094
|
-
},
|
|
3147
|
+
}],
|
|
3095
3148
|
"variant": variant
|
|
3096
3149
|
}, _isSlot$7(_slot = tools.map(({
|
|
3097
3150
|
key,
|
|
@@ -3103,16 +3156,23 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3103
3156
|
const isActive = !!_editor && resolveContextableValue(context, active);
|
|
3104
3157
|
const isDisabled = !inputControl.canOperation || !!_editor && resolveContextableValue(context, disabled);
|
|
3105
3158
|
let iconName;
|
|
3159
|
+
let child;
|
|
3106
3160
|
|
|
3107
3161
|
if (typeof icon === 'function') {
|
|
3108
3162
|
if (_editor) {
|
|
3109
|
-
|
|
3163
|
+
const _child = icon(context);
|
|
3164
|
+
|
|
3165
|
+
if (typeof _child === 'function') {
|
|
3166
|
+
child = _child();
|
|
3167
|
+
} else {
|
|
3168
|
+
iconName = child;
|
|
3169
|
+
}
|
|
3110
3170
|
}
|
|
3111
3171
|
} else {
|
|
3112
3172
|
iconName = icon;
|
|
3113
3173
|
}
|
|
3114
3174
|
|
|
3115
|
-
if (!iconName) return;
|
|
3175
|
+
if (!iconName && child == null) return;
|
|
3116
3176
|
return vue.createVNode(VButton, {
|
|
3117
3177
|
"tabindex": -1,
|
|
3118
3178
|
"key": key,
|
|
@@ -3120,7 +3180,9 @@ const VWysiwygEditor = vue.defineComponent({
|
|
|
3120
3180
|
"onClick": ev => onClick(context, ev),
|
|
3121
3181
|
"color": isActive ? toolButtonActiveColor : undefined,
|
|
3122
3182
|
"disabled": isDisabled
|
|
3123
|
-
},
|
|
3183
|
+
}, _isSlot$7(child) ? child : {
|
|
3184
|
+
default: () => [child]
|
|
3185
|
+
});
|
|
3124
3186
|
})) ? _slot : {
|
|
3125
3187
|
default: () => [_slot]
|
|
3126
3188
|
});
|
|
@@ -3204,190 +3266,217 @@ function resolveContextableValue(ctx, source) {
|
|
|
3204
3266
|
return typeof source === 'function' ? source(ctx) : source;
|
|
3205
3267
|
}
|
|
3206
3268
|
|
|
3207
|
-
const PROBLEM_CLASS_NAME = 'v-linter__problem';
|
|
3208
|
-
const ISSUE_ICON_CLASS_NAME = 'v-linter__issue-icon';
|
|
3209
|
-
const
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
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
|
+
} = issue;
|
|
3302
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3303
|
+
decorations.push(prosemirrorView.Decoration.inline(issue.from, issue.to, {
|
|
3304
|
+
class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
|
|
3305
|
+
'data-issue-id': issue.id,
|
|
3306
|
+
title: typeof message === 'string' ? message : undefined
|
|
3307
|
+
}), prosemirrorView.Decoration.widget(issue.from, view => renderIcon(view, issue)));
|
|
3308
|
+
});
|
|
3309
|
+
const decorationSet = prosemirrorView.DecorationSet.create(doc, decorations);
|
|
3310
|
+
return {
|
|
3311
|
+
issues,
|
|
3312
|
+
decorationSet
|
|
3313
|
+
};
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
const WysiwygLinter = createWysiwygExtension(ctx => {
|
|
3317
|
+
function showMenu(view, issue, event) {
|
|
3318
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3319
|
+
const variant = ctx.vui.setting('containedVariant');
|
|
3320
|
+
const scope = ctx.vui.setting(`${issue.level}Scope`);
|
|
3321
|
+
return ctx.vui.menu({
|
|
3322
|
+
activator: event,
|
|
3323
|
+
content: stack => vue.createVNode("div", {
|
|
3324
|
+
"class": "v-linter__issue-menu__body"
|
|
3325
|
+
}, [vue.createVNode("div", {
|
|
3326
|
+
"class": ['v-linter__issue-menu__message', `${scope}-scope ${variant}`]
|
|
3327
|
+
}, [message]), issue.fix.length && vue.createVNode("div", {
|
|
3328
|
+
"class": "v-linter__issue-menu__fixers"
|
|
3329
|
+
}, [issue.fix.map((fixer, index) => vue.createVNode("div", {
|
|
3330
|
+
"key": index,
|
|
3331
|
+
"class": "v-linter__issue-menu__fixer"
|
|
3332
|
+
}, [vue.createVNode("button", {
|
|
3333
|
+
"type": "button",
|
|
3334
|
+
"class": "v-linter__issue-menu__fixer__button",
|
|
3335
|
+
"onClick": () => {
|
|
3336
|
+
stack.close();
|
|
3337
|
+
fixer.handler(view, issue);
|
|
3338
|
+
}
|
|
3339
|
+
}, [vue.createVNode("span", {
|
|
3340
|
+
"class": "v-linter__issue-menu__fixer__button__message"
|
|
3341
|
+
}, [resolveWysiwygLinterFixMessage(fixer.message)])])]))])])
|
|
3342
|
+
});
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
return core.Extension.create({
|
|
3346
|
+
name: 'linter',
|
|
3347
|
+
|
|
3348
|
+
addOptions() {
|
|
3349
|
+
return {
|
|
3350
|
+
plugins: []
|
|
3351
|
+
};
|
|
3352
|
+
},
|
|
3353
|
+
|
|
3354
|
+
addStorage() {
|
|
3355
|
+
return {
|
|
3356
|
+
issues: []
|
|
3357
|
+
};
|
|
3358
|
+
},
|
|
3359
|
+
|
|
3360
|
+
addProseMirrorPlugins() {
|
|
3361
|
+
const {
|
|
3362
|
+
plugins
|
|
3363
|
+
} = this.options;
|
|
3364
|
+
const {
|
|
3365
|
+
storage
|
|
3366
|
+
} = this;
|
|
3367
|
+
|
|
3368
|
+
const runAll = doc => {
|
|
3369
|
+
const {
|
|
3370
|
+
issues,
|
|
3371
|
+
decorationSet
|
|
3372
|
+
} = runAllLinterPlugins(doc, plugins);
|
|
3373
|
+
storage.issues = issues;
|
|
3374
|
+
return decorationSet;
|
|
3375
|
+
};
|
|
3376
|
+
|
|
3377
|
+
const getIssue = id => storage.issues.find(issue => issue.id === id);
|
|
3378
|
+
|
|
3379
|
+
const getIssueElementByEvent = source => {
|
|
3380
|
+
if (!source || !(source instanceof HTMLElement)) {
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
const issueId = source.getAttribute(ISSUE_DATASET_NAME);
|
|
3385
|
+
const issue = issueId && getIssue(issueId);
|
|
3386
|
+
if (!issue) return;
|
|
3387
|
+
return {
|
|
3388
|
+
issue
|
|
3389
|
+
};
|
|
3390
|
+
};
|
|
3391
|
+
|
|
3392
|
+
return [new prosemirrorState.Plugin({
|
|
3393
|
+
key: new prosemirrorState.PluginKey('linter'),
|
|
3394
|
+
state: {
|
|
3395
|
+
init(_, {
|
|
3396
|
+
doc
|
|
3397
|
+
}) {
|
|
3398
|
+
return runAll(doc);
|
|
3399
|
+
},
|
|
3400
|
+
|
|
3401
|
+
apply(transaction, oldState) {
|
|
3402
|
+
return transaction.docChanged ? runAll(transaction.doc) : oldState;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
},
|
|
3406
|
+
props: {
|
|
3407
|
+
decorations(state) {
|
|
3408
|
+
return this.getState(state);
|
|
3409
|
+
},
|
|
3410
|
+
|
|
3411
|
+
handleClick(view, _, event) {
|
|
3412
|
+
const info = getIssueElementByEvent(event.target);
|
|
3413
|
+
|
|
3414
|
+
if (!info) {
|
|
3415
|
+
return false;
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
const {
|
|
3419
|
+
issue
|
|
3420
|
+
} = info;
|
|
3421
|
+
const {
|
|
3422
|
+
from,
|
|
3423
|
+
to
|
|
3424
|
+
} = issue;
|
|
3425
|
+
|
|
3426
|
+
const focus = () => view.dispatch(view.state.tr.setSelection(prosemirrorState.TextSelection.create(view.state.doc, from, to)).scrollIntoView());
|
|
3427
|
+
|
|
3428
|
+
focus();
|
|
3429
|
+
showMenu(view, issue, event);
|
|
3430
|
+
return true;
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
}
|
|
3434
|
+
})];
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
});
|
|
3438
|
+
});
|
|
3439
|
+
|
|
3440
|
+
let IDX = 256, BUFFER;
|
|
3441
|
+
const HEX = [];
|
|
3442
|
+
while (IDX--)
|
|
3443
|
+
HEX[IDX] = (IDX + 256).toString(16).substring(1);
|
|
3444
|
+
function cheepUUID() {
|
|
3445
|
+
let i = 0, num, out = '';
|
|
3446
|
+
if (!BUFFER || IDX + 16 > 256) {
|
|
3447
|
+
BUFFER = Array((i = 256));
|
|
3448
|
+
while (i--)
|
|
3449
|
+
BUFFER[i] = (256 * Math.random()) | 0;
|
|
3450
|
+
i = IDX = 0;
|
|
3245
3451
|
}
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3452
|
+
for (; i < 16; i++) {
|
|
3453
|
+
num = BUFFER[IDX + i];
|
|
3454
|
+
if (i == 6)
|
|
3455
|
+
out += HEX[(num & 15) | 64];
|
|
3456
|
+
else if (i == 8)
|
|
3457
|
+
out += HEX[(num & 63) | 128];
|
|
3458
|
+
else
|
|
3459
|
+
out += HEX[num];
|
|
3460
|
+
if (i & 1 && i > 1 && i < 11)
|
|
3461
|
+
out += '-';
|
|
3249
3462
|
}
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
}
|
|
3254
|
-
function getMenuElement(source) {
|
|
3255
|
-
return getIssueElement(source, ISSUE_MENU_CLASS_NAME);
|
|
3256
|
-
}
|
|
3257
|
-
function getProblemElement(source) {
|
|
3258
|
-
return getIssueElement(source, PROBLEM_CLASS_NAME);
|
|
3259
|
-
}
|
|
3260
|
-
function runAllLinterPlugins(doc, plugins) {
|
|
3261
|
-
const decorations = [];
|
|
3262
|
-
const results = plugins
|
|
3263
|
-
.map((RegisteredLinterPlugin) => {
|
|
3264
|
-
return new RegisteredLinterPlugin(doc).scan().getResults();
|
|
3265
|
-
})
|
|
3266
|
-
.flat();
|
|
3267
|
-
results.forEach((issue) => {
|
|
3268
|
-
const { level = 'warning' } = issue;
|
|
3269
|
-
decorations.push(prosemirrorView.Decoration.inline(issue.from, issue.to, {
|
|
3270
|
-
class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
|
|
3271
|
-
'data-issue': JSON.stringify(issue),
|
|
3272
|
-
title: issue.message,
|
|
3273
|
-
}), prosemirrorView.Decoration.widget(issue.from, (view) => renderIcon(view, issue)), prosemirrorView.Decoration.widget(issue.from, (view) => renderMenu(view, issue)));
|
|
3274
|
-
});
|
|
3275
|
-
return prosemirrorView.DecorationSet.create(doc, decorations);
|
|
3276
|
-
}
|
|
3277
|
-
function updateMenusPosition(editorElement) {
|
|
3278
|
-
const { left, right } = editorElement.getBoundingClientRect();
|
|
3279
|
-
const menus = Array.from(editorElement.querySelectorAll(`.${ISSUE_MENU_CLASS_NAME}`));
|
|
3280
|
-
menus.forEach((menu) => {
|
|
3281
|
-
const { left: menuLeft, right: menuRight } = menu.getBoundingClientRect();
|
|
3282
|
-
const overflow = menuRight - right;
|
|
3283
|
-
let offset = 0;
|
|
3284
|
-
if (overflow > 0) {
|
|
3285
|
-
offset = -overflow;
|
|
3286
|
-
if (menuLeft + offset < left) {
|
|
3287
|
-
offset = 0;
|
|
3288
|
-
}
|
|
3289
|
-
}
|
|
3290
|
-
menu.style.transform = `translateX(${offset}px)`;
|
|
3291
|
-
});
|
|
3292
|
-
}
|
|
3293
|
-
const debouncedUpdateMenusPosition = helpers.debounce(updateMenusPosition, 250);
|
|
3294
|
-
const Linter = core.Extension.create({
|
|
3295
|
-
name: 'linter',
|
|
3296
|
-
addOptions() {
|
|
3297
|
-
return {
|
|
3298
|
-
plugins: [],
|
|
3299
|
-
};
|
|
3300
|
-
},
|
|
3301
|
-
onCreate() {
|
|
3302
|
-
const { dom } = this.editor.view;
|
|
3303
|
-
debouncedUpdateMenusPosition(dom);
|
|
3304
|
-
},
|
|
3305
|
-
onUpdate() {
|
|
3306
|
-
const { dom } = this.editor.view;
|
|
3307
|
-
debouncedUpdateMenusPosition(dom);
|
|
3308
|
-
},
|
|
3309
|
-
addProseMirrorPlugins() {
|
|
3310
|
-
const { plugins } = this.options;
|
|
3311
|
-
return [
|
|
3312
|
-
new prosemirrorState.Plugin({
|
|
3313
|
-
key: new prosemirrorState.PluginKey('linter'),
|
|
3314
|
-
state: {
|
|
3315
|
-
init(_, { doc }) {
|
|
3316
|
-
return runAllLinterPlugins(doc, plugins);
|
|
3317
|
-
},
|
|
3318
|
-
apply(transaction, oldState) {
|
|
3319
|
-
return transaction.docChanged
|
|
3320
|
-
? runAllLinterPlugins(transaction.doc, plugins)
|
|
3321
|
-
: oldState;
|
|
3322
|
-
},
|
|
3323
|
-
},
|
|
3324
|
-
props: {
|
|
3325
|
-
decorations(state) {
|
|
3326
|
-
return this.getState(state);
|
|
3327
|
-
},
|
|
3328
|
-
handleClick(view, _, event) {
|
|
3329
|
-
const activeMenus = Array.from(view.dom.querySelectorAll(`.${ISSUE_MENU_CLASS_NAME}--active`));
|
|
3330
|
-
activeMenus.forEach((menu) => menu.classList.remove(`${ISSUE_MENU_CLASS_NAME}--active`));
|
|
3331
|
-
const problem = getProblemElement(event.target);
|
|
3332
|
-
const issueString = problem && problem.dataset['issue'];
|
|
3333
|
-
const issue = issueString && JSON.parse(issueString);
|
|
3334
|
-
if (issue) {
|
|
3335
|
-
const menuWrapper = problem.previousElementSibling;
|
|
3336
|
-
const menu = menuWrapper &&
|
|
3337
|
-
menuWrapper.querySelector(`.${ISSUE_MENU_CLASS_NAME}`);
|
|
3338
|
-
menu && menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3339
|
-
const { from, to } = issue;
|
|
3340
|
-
view.dispatch(view.state.tr
|
|
3341
|
-
.setSelection(prosemirrorState.TextSelection.create(view.state.doc, from, to))
|
|
3342
|
-
.scrollIntoView());
|
|
3343
|
-
return true;
|
|
3344
|
-
}
|
|
3345
|
-
const menu = getMenuElement(event.target);
|
|
3346
|
-
if (menu) {
|
|
3347
|
-
menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3348
|
-
}
|
|
3349
|
-
const target = getIconElement(event.target);
|
|
3350
|
-
if (target && target.issue) {
|
|
3351
|
-
const menuWrapper = target.nextElementSibling;
|
|
3352
|
-
const menu = menuWrapper &&
|
|
3353
|
-
menuWrapper.querySelector(`.${ISSUE_MENU_CLASS_NAME}`);
|
|
3354
|
-
menu && menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3355
|
-
const { from, to } = target.issue;
|
|
3356
|
-
view.dispatch(view.state.tr
|
|
3357
|
-
.setSelection(prosemirrorState.TextSelection.create(view.state.doc, from, to))
|
|
3358
|
-
.scrollIntoView());
|
|
3359
|
-
return true;
|
|
3360
|
-
}
|
|
3361
|
-
return false;
|
|
3362
|
-
},
|
|
3363
|
-
handleDoubleClick(view, _, event) {
|
|
3364
|
-
const target = getIconElement(event.target);
|
|
3365
|
-
if (target && target.issue) {
|
|
3366
|
-
const prob = target.issue;
|
|
3367
|
-
if (prob.fix) {
|
|
3368
|
-
prob.fix(view, prob);
|
|
3369
|
-
view.focus();
|
|
3370
|
-
return true;
|
|
3371
|
-
}
|
|
3372
|
-
}
|
|
3373
|
-
return false;
|
|
3374
|
-
},
|
|
3375
|
-
},
|
|
3376
|
-
}),
|
|
3377
|
-
];
|
|
3378
|
-
},
|
|
3379
|
-
});
|
|
3463
|
+
IDX++;
|
|
3464
|
+
return out;
|
|
3465
|
+
}
|
|
3380
3466
|
|
|
3381
|
-
class
|
|
3467
|
+
class WysiwygLinterPlugin {
|
|
3382
3468
|
doc;
|
|
3383
3469
|
results = [];
|
|
3384
3470
|
constructor(doc) {
|
|
3385
3471
|
this.doc = doc;
|
|
3386
3472
|
}
|
|
3387
3473
|
record(result) {
|
|
3474
|
+
const { fix = [] } = result;
|
|
3388
3475
|
this.results.push({
|
|
3389
3476
|
level: 'error',
|
|
3477
|
+
id: cheepUUID(),
|
|
3390
3478
|
...result,
|
|
3479
|
+
fix: Array.isArray(fix) ? fix : [fix],
|
|
3391
3480
|
});
|
|
3392
3481
|
}
|
|
3393
3482
|
scan() {
|
|
@@ -3398,35 +3487,45 @@ class LinterPlugin {
|
|
|
3398
3487
|
}
|
|
3399
3488
|
}
|
|
3400
3489
|
|
|
3401
|
-
function
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3490
|
+
function WysiwygLinterBadWords(words) {
|
|
3491
|
+
const regex = new RegExp(`\\b(${words.join('|')})\\b`);
|
|
3492
|
+
return class WysiwygLinterBadWords extends WysiwygLinterPlugin {
|
|
3493
|
+
scan() {
|
|
3494
|
+
this.doc.descendants((node, position) => {
|
|
3495
|
+
if (!node.isText) {
|
|
3496
|
+
return;
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
const matches = regex.exec(node.text);
|
|
3500
|
+
|
|
3501
|
+
if (matches) {
|
|
3502
|
+
const fixValue = matches[0] + '!!!!!';
|
|
3503
|
+
this.record({
|
|
3504
|
+
level: 'warning',
|
|
3505
|
+
message: `Try not to say '${matches[0]}'`,
|
|
3506
|
+
from: position + matches.index,
|
|
3507
|
+
to: position + matches.index + matches[0].length,
|
|
3508
|
+
fix: [{
|
|
3509
|
+
message: () => vue.createVNode("span", null, [vue.createVNode("code", null, [fixValue]), vue.createTextVNode("\u306B\u4FEE\u6B63\u3059\u308B\u3002")]),
|
|
3510
|
+
handler: () => {
|
|
3511
|
+
console.log('hoge');
|
|
3512
|
+
}
|
|
3513
|
+
}, {
|
|
3514
|
+
message: 'どうにかする',
|
|
3515
|
+
handler: () => {
|
|
3516
|
+
console.log('hoge');
|
|
3517
|
+
}
|
|
3518
|
+
}]
|
|
3519
|
+
});
|
|
3520
|
+
}
|
|
3521
|
+
});
|
|
3522
|
+
return this;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
};
|
|
3427
3526
|
}
|
|
3428
3527
|
|
|
3429
|
-
class
|
|
3528
|
+
class WysiwygLinterHeadingLevel extends WysiwygLinterPlugin {
|
|
3430
3529
|
fixHeader(level) {
|
|
3431
3530
|
return function ({ state, dispatch }, issue) {
|
|
3432
3531
|
dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level }));
|
|
@@ -3443,7 +3542,10 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3443
3542
|
message: `Heading too small (${level} under ${lastHeadLevel})`,
|
|
3444
3543
|
from: position + 1,
|
|
3445
3544
|
to: position + 1 + node.content.size,
|
|
3446
|
-
fix:
|
|
3545
|
+
fix: {
|
|
3546
|
+
message: '修正する',
|
|
3547
|
+
handler: this.fixHeader(lastHeadLevel + 1),
|
|
3548
|
+
},
|
|
3447
3549
|
});
|
|
3448
3550
|
}
|
|
3449
3551
|
lastHeadLevel = level;
|
|
@@ -3453,7 +3555,7 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3453
3555
|
}
|
|
3454
3556
|
}
|
|
3455
3557
|
|
|
3456
|
-
class
|
|
3558
|
+
class WysiwygLinterPunctuation extends WysiwygLinterPlugin {
|
|
3457
3559
|
regex = / ([,.!?:]) ?/g;
|
|
3458
3560
|
fix(replacement) {
|
|
3459
3561
|
return function ({ state, dispatch }, issue) {
|
|
@@ -3474,7 +3576,10 @@ class Punctuation extends LinterPlugin {
|
|
|
3474
3576
|
message: 'Suspicious spacing around punctuation',
|
|
3475
3577
|
from: position + matches.index,
|
|
3476
3578
|
to: position + matches.index + matches[0].length,
|
|
3477
|
-
fix:
|
|
3579
|
+
fix: {
|
|
3580
|
+
message: 'Fix it!!!',
|
|
3581
|
+
handler: this.fix(`${matches[1]} `),
|
|
3582
|
+
},
|
|
3478
3583
|
});
|
|
3479
3584
|
}
|
|
3480
3585
|
});
|
|
@@ -3482,6 +3587,49 @@ class Punctuation extends LinterPlugin {
|
|
|
3482
3587
|
}
|
|
3483
3588
|
}
|
|
3484
3589
|
|
|
3590
|
+
const WysiwygColorExtension = core.Extension.create({
|
|
3591
|
+
name: 'color',
|
|
3592
|
+
addOptions() {
|
|
3593
|
+
return {
|
|
3594
|
+
types: ['textStyle'],
|
|
3595
|
+
};
|
|
3596
|
+
},
|
|
3597
|
+
addGlobalAttributes() {
|
|
3598
|
+
return [
|
|
3599
|
+
{
|
|
3600
|
+
types: this.options.types,
|
|
3601
|
+
attributes: {
|
|
3602
|
+
color: {
|
|
3603
|
+
default: null,
|
|
3604
|
+
parseHTML: (element) => element.style.color.replace(/['"]+/g, ''),
|
|
3605
|
+
renderHTML: (attributes) => {
|
|
3606
|
+
if (!attributes.color) {
|
|
3607
|
+
return {};
|
|
3608
|
+
}
|
|
3609
|
+
return {
|
|
3610
|
+
style: `color: ${attributes.color}`,
|
|
3611
|
+
};
|
|
3612
|
+
},
|
|
3613
|
+
},
|
|
3614
|
+
},
|
|
3615
|
+
},
|
|
3616
|
+
];
|
|
3617
|
+
},
|
|
3618
|
+
addCommands() {
|
|
3619
|
+
return {
|
|
3620
|
+
setColor: (color) => ({ chain }) => {
|
|
3621
|
+
return chain().setMark('textStyle', { color }).run();
|
|
3622
|
+
},
|
|
3623
|
+
unsetColor: () => ({ chain }) => {
|
|
3624
|
+
return chain()
|
|
3625
|
+
.setMark('textStyle', { color: null })
|
|
3626
|
+
.removeEmptyTextStyle()
|
|
3627
|
+
.run();
|
|
3628
|
+
},
|
|
3629
|
+
};
|
|
3630
|
+
},
|
|
3631
|
+
});
|
|
3632
|
+
|
|
3485
3633
|
const WysiwygBulletListTool = (vui, options) => {
|
|
3486
3634
|
const tool = {
|
|
3487
3635
|
key: 'bulletList',
|
|
@@ -3622,18 +3770,73 @@ const WysiwygOrderedListTool = (vui, options) => {
|
|
|
3622
3770
|
return tool;
|
|
3623
3771
|
};
|
|
3624
3772
|
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
};
|
|
3773
|
+
function createWysiwygColorTool(opts) {
|
|
3774
|
+
const WysiwygColorTool = vui => {
|
|
3775
|
+
const tool = {
|
|
3776
|
+
key: 'textColor',
|
|
3777
|
+
// active: ({ editor }) => editor.isActive('textStyle'),
|
|
3778
|
+
icon: ({
|
|
3779
|
+
editor
|
|
3780
|
+
}) => () => {
|
|
3781
|
+
const color = editor.getAttributes('textStyle').color;
|
|
3782
|
+
const style = {
|
|
3783
|
+
color
|
|
3784
|
+
};
|
|
3785
|
+
return vue.createVNode("span", {
|
|
3786
|
+
"class": "v-wysiwyg-color-tool__button"
|
|
3787
|
+
}, [vue.createVNode(VIcon, {
|
|
3788
|
+
"class": "v-wysiwyg-color-tool__button__icon",
|
|
3789
|
+
"name": vui.icon('editorTextColor')
|
|
3790
|
+
}, null), vue.createVNode("span", {
|
|
3791
|
+
"class": "v-wysiwyg-color-tool__button__bar",
|
|
3792
|
+
"style": style
|
|
3793
|
+
}, null)]);
|
|
3794
|
+
},
|
|
3795
|
+
onClick: (ctx, ev) => {
|
|
3796
|
+
ctx.vui.menu({
|
|
3797
|
+
class: 'v-wysiwyg-color-tool__menu',
|
|
3798
|
+
activator: ev,
|
|
3799
|
+
content: stack => vue.createVNode("div", {
|
|
3800
|
+
"class": ['v-wysiwyg-color-tool__items', {
|
|
3801
|
+
'v-wysiwyg-color-tool__items--with-label': opts.withLabel
|
|
3802
|
+
}]
|
|
3803
|
+
}, [opts.items.map((item, index) => vue.createVNode("button", {
|
|
3804
|
+
"key": item.key == null ? index : item.key,
|
|
3805
|
+
"class": "v-wysiwyg-color-tool__item",
|
|
3806
|
+
"type": "button",
|
|
3807
|
+
"onClick": () => {
|
|
3808
|
+
const {
|
|
3809
|
+
color
|
|
3810
|
+
} = item;
|
|
3811
|
+
let command = ctx.editor.chain().focus();
|
|
3812
|
+
|
|
3813
|
+
if (color) {
|
|
3814
|
+
command = command.setColor(color);
|
|
3815
|
+
} else {
|
|
3816
|
+
command = command.unsetColor();
|
|
3817
|
+
}
|
|
3818
|
+
|
|
3819
|
+
command.run();
|
|
3820
|
+
stack.close();
|
|
3821
|
+
}
|
|
3822
|
+
}, [vue.createVNode("span", {
|
|
3823
|
+
"class": "v-wysiwyg-color-tool__item__color",
|
|
3824
|
+
"style": item.color ? {
|
|
3825
|
+
color: item.color
|
|
3826
|
+
} : {}
|
|
3827
|
+
}, null), opts.withLabel && vue.createVNode("span", {
|
|
3828
|
+
"class": "v-wysiwyg-color-tool__item__name"
|
|
3829
|
+
}, [item.name])]))])
|
|
3830
|
+
});
|
|
3831
|
+
},
|
|
3832
|
+
floating: true,
|
|
3833
|
+
extensions: [TextStyle__default, WysiwygColorExtension]
|
|
3834
|
+
};
|
|
3835
|
+
return tool;
|
|
3836
|
+
};
|
|
3837
|
+
|
|
3838
|
+
return WysiwygColorTool;
|
|
3839
|
+
}
|
|
3637
3840
|
|
|
3638
3841
|
const {
|
|
3639
3842
|
props,
|
|
@@ -5250,6 +5453,10 @@ class VuiService {
|
|
|
5250
5453
|
return this.stack.snackbar(...args);
|
|
5251
5454
|
}
|
|
5252
5455
|
|
|
5456
|
+
menu(...args) {
|
|
5457
|
+
return this.stack.menu(...args);
|
|
5458
|
+
}
|
|
5459
|
+
|
|
5253
5460
|
formPrompt(settings, slot) {
|
|
5254
5461
|
let form;
|
|
5255
5462
|
const options = {
|
|
@@ -5407,16 +5614,11 @@ exports.VSnackbar = vueKit.VSnackbar;
|
|
|
5407
5614
|
exports.VTooltip = vueKit.VTooltip;
|
|
5408
5615
|
exports.ICON_NAMES = iconFont.ICON_NAMES;
|
|
5409
5616
|
exports.AVATAR_SIZES = AVATAR_SIZES;
|
|
5410
|
-
exports.BadWords = BadWords;
|
|
5411
5617
|
exports.CHIP_SIZES = CHIP_SIZES;
|
|
5412
5618
|
exports.CONTROL_FIELD_VARIANTS = CONTROL_FIELD_VARIANTS;
|
|
5413
5619
|
exports.CONTROL_LOADING_SPINNER_SIZES = CONTROL_LOADING_SPINNER_SIZES;
|
|
5414
5620
|
exports.CONTROL_SIZES = CONTROL_SIZES;
|
|
5415
|
-
exports.HeadingLevel = HeadingLevel;
|
|
5416
|
-
exports.Linter = Linter;
|
|
5417
|
-
exports.LinterPlugin = LinterPlugin;
|
|
5418
5621
|
exports.PAGINATION_ALIGNS = PAGINATION_ALIGNS;
|
|
5419
|
-
exports.Punctuation = Punctuation;
|
|
5420
5622
|
exports.VApp = VApp;
|
|
5421
5623
|
exports.VAvatar = VAvatar;
|
|
5422
5624
|
exports.VBreadcrumbs = VBreadcrumbs;
|
|
@@ -5479,14 +5681,19 @@ exports.VuiInjectionKey = VuiInjectionKey;
|
|
|
5479
5681
|
exports.VuiPlugin = VuiPlugin;
|
|
5480
5682
|
exports.VuiService = VuiService;
|
|
5481
5683
|
exports.WysiwygBulletListTool = WysiwygBulletListTool;
|
|
5684
|
+
exports.WysiwygColorExtension = WysiwygColorExtension;
|
|
5482
5685
|
exports.WysiwygEditorInitializeContext = WysiwygEditorInitializeContext;
|
|
5483
5686
|
exports.WysiwygFormatBoldTool = WysiwygFormatBoldTool;
|
|
5484
5687
|
exports.WysiwygFormatItalicTool = WysiwygFormatItalicTool;
|
|
5485
5688
|
exports.WysiwygFormatUnderlineTool = WysiwygFormatUnderlineTool;
|
|
5486
5689
|
exports.WysiwygHistoryTool = WysiwygHistoryTool;
|
|
5487
5690
|
exports.WysiwygLinkTool = WysiwygLinkTool;
|
|
5691
|
+
exports.WysiwygLinter = WysiwygLinter;
|
|
5692
|
+
exports.WysiwygLinterBadWords = WysiwygLinterBadWords;
|
|
5693
|
+
exports.WysiwygLinterHeadingLevel = WysiwygLinterHeadingLevel;
|
|
5694
|
+
exports.WysiwygLinterPlugin = WysiwygLinterPlugin;
|
|
5695
|
+
exports.WysiwygLinterPunctuation = WysiwygLinterPunctuation;
|
|
5488
5696
|
exports.WysiwygOrderedListTool = WysiwygOrderedListTool;
|
|
5489
|
-
exports.WysiwygTextColorTool = WysiwygTextColorTool;
|
|
5490
5697
|
exports.configureDataTableDefaults = configureDataTableDefaults;
|
|
5491
5698
|
exports.createAvatarProps = createAvatarProps;
|
|
5492
5699
|
exports.createCardProps = createCardProps;
|
|
@@ -5500,6 +5707,8 @@ exports.createPaperBaseProps = createPaperBaseProps;
|
|
|
5500
5707
|
exports.createPaperProps = createPaperProps;
|
|
5501
5708
|
exports.createRequiredChipRenderer = createRequiredChipRenderer;
|
|
5502
5709
|
exports.createVFormProps = createVFormProps;
|
|
5710
|
+
exports.createWysiwygColorTool = createWysiwygColorTool;
|
|
5711
|
+
exports.createWysiwygExtension = createWysiwygExtension;
|
|
5503
5712
|
exports.defineFormSelectorComponent = defineFormSelectorComponent;
|
|
5504
5713
|
exports.iconProps = iconProps;
|
|
5505
5714
|
exports.installVuiPlugin = installVuiPlugin;
|