@fastkit/vui 0.7.61 → 0.7.66
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 +443 -228
- package/dist/vui.cjs.prod.js +443 -228
- package/dist/vui.css +166 -12
- package/dist/vui.d.ts +103 -54
- package/dist/vui.min.css +1 -1
- package/dist/vui.min.css.map +1 -1
- package/dist/vui.mjs +437 -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 +214 -0
- package/src/components/VWysiwygEditor/extensions/linter/LinterPlugin.ts +32 -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.prod.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,223 @@ 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
|
+
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;
|
|
3245
3456
|
}
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
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 += '-';
|
|
3249
3467
|
}
|
|
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
|
-
});
|
|
3468
|
+
IDX++;
|
|
3469
|
+
return out;
|
|
3470
|
+
}
|
|
3380
3471
|
|
|
3381
|
-
class
|
|
3472
|
+
class WysiwygLinterPlugin {
|
|
3382
3473
|
doc;
|
|
3383
3474
|
results = [];
|
|
3384
3475
|
constructor(doc) {
|
|
3385
3476
|
this.doc = doc;
|
|
3386
3477
|
}
|
|
3387
3478
|
record(result) {
|
|
3479
|
+
const { fix = [], icon = false } = result;
|
|
3388
3480
|
this.results.push({
|
|
3389
3481
|
level: 'error',
|
|
3482
|
+
id: cheepUUID(),
|
|
3390
3483
|
...result,
|
|
3484
|
+
fix: Array.isArray(fix) ? fix : [fix],
|
|
3485
|
+
icon,
|
|
3391
3486
|
});
|
|
3392
3487
|
}
|
|
3393
3488
|
scan() {
|
|
@@ -3398,35 +3493,45 @@ class LinterPlugin {
|
|
|
3398
3493
|
}
|
|
3399
3494
|
}
|
|
3400
3495
|
|
|
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
|
-
|
|
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
|
+
};
|
|
3427
3532
|
}
|
|
3428
3533
|
|
|
3429
|
-
class
|
|
3534
|
+
class WysiwygLinterHeadingLevel extends WysiwygLinterPlugin {
|
|
3430
3535
|
fixHeader(level) {
|
|
3431
3536
|
return function ({ state, dispatch }, issue) {
|
|
3432
3537
|
dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level }));
|
|
@@ -3443,7 +3548,10 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3443
3548
|
message: `Heading too small (${level} under ${lastHeadLevel})`,
|
|
3444
3549
|
from: position + 1,
|
|
3445
3550
|
to: position + 1 + node.content.size,
|
|
3446
|
-
fix:
|
|
3551
|
+
fix: {
|
|
3552
|
+
message: '修正する',
|
|
3553
|
+
handler: this.fixHeader(lastHeadLevel + 1),
|
|
3554
|
+
},
|
|
3447
3555
|
});
|
|
3448
3556
|
}
|
|
3449
3557
|
lastHeadLevel = level;
|
|
@@ -3453,7 +3561,7 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3453
3561
|
}
|
|
3454
3562
|
}
|
|
3455
3563
|
|
|
3456
|
-
class
|
|
3564
|
+
class WysiwygLinterPunctuation extends WysiwygLinterPlugin {
|
|
3457
3565
|
regex = / ([,.!?:]) ?/g;
|
|
3458
3566
|
fix(replacement) {
|
|
3459
3567
|
return function ({ state, dispatch }, issue) {
|
|
@@ -3474,7 +3582,10 @@ class Punctuation extends LinterPlugin {
|
|
|
3474
3582
|
message: 'Suspicious spacing around punctuation',
|
|
3475
3583
|
from: position + matches.index,
|
|
3476
3584
|
to: position + matches.index + matches[0].length,
|
|
3477
|
-
fix:
|
|
3585
|
+
fix: {
|
|
3586
|
+
message: 'Fix it!!!',
|
|
3587
|
+
handler: this.fix(`${matches[1]} `),
|
|
3588
|
+
},
|
|
3478
3589
|
});
|
|
3479
3590
|
}
|
|
3480
3591
|
});
|
|
@@ -3482,6 +3593,49 @@ class Punctuation extends LinterPlugin {
|
|
|
3482
3593
|
}
|
|
3483
3594
|
}
|
|
3484
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
|
+
|
|
3485
3639
|
const WysiwygBulletListTool = (vui, options) => {
|
|
3486
3640
|
const tool = {
|
|
3487
3641
|
key: 'bulletList',
|
|
@@ -3622,18 +3776,73 @@ const WysiwygOrderedListTool = (vui, options) => {
|
|
|
3622
3776
|
return tool;
|
|
3623
3777
|
};
|
|
3624
3778
|
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
};
|
|
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
|
+
}
|
|
3637
3846
|
|
|
3638
3847
|
const {
|
|
3639
3848
|
props,
|
|
@@ -5250,6 +5459,10 @@ class VuiService {
|
|
|
5250
5459
|
return this.stack.snackbar(...args);
|
|
5251
5460
|
}
|
|
5252
5461
|
|
|
5462
|
+
menu(...args) {
|
|
5463
|
+
return this.stack.menu(...args);
|
|
5464
|
+
}
|
|
5465
|
+
|
|
5253
5466
|
formPrompt(settings, slot) {
|
|
5254
5467
|
let form;
|
|
5255
5468
|
const options = {
|
|
@@ -5407,16 +5620,11 @@ exports.VSnackbar = vueKit.VSnackbar;
|
|
|
5407
5620
|
exports.VTooltip = vueKit.VTooltip;
|
|
5408
5621
|
exports.ICON_NAMES = iconFont.ICON_NAMES;
|
|
5409
5622
|
exports.AVATAR_SIZES = AVATAR_SIZES;
|
|
5410
|
-
exports.BadWords = BadWords;
|
|
5411
5623
|
exports.CHIP_SIZES = CHIP_SIZES;
|
|
5412
5624
|
exports.CONTROL_FIELD_VARIANTS = CONTROL_FIELD_VARIANTS;
|
|
5413
5625
|
exports.CONTROL_LOADING_SPINNER_SIZES = CONTROL_LOADING_SPINNER_SIZES;
|
|
5414
5626
|
exports.CONTROL_SIZES = CONTROL_SIZES;
|
|
5415
|
-
exports.HeadingLevel = HeadingLevel;
|
|
5416
|
-
exports.Linter = Linter;
|
|
5417
|
-
exports.LinterPlugin = LinterPlugin;
|
|
5418
5627
|
exports.PAGINATION_ALIGNS = PAGINATION_ALIGNS;
|
|
5419
|
-
exports.Punctuation = Punctuation;
|
|
5420
5628
|
exports.VApp = VApp;
|
|
5421
5629
|
exports.VAvatar = VAvatar;
|
|
5422
5630
|
exports.VBreadcrumbs = VBreadcrumbs;
|
|
@@ -5479,14 +5687,19 @@ exports.VuiInjectionKey = VuiInjectionKey;
|
|
|
5479
5687
|
exports.VuiPlugin = VuiPlugin;
|
|
5480
5688
|
exports.VuiService = VuiService;
|
|
5481
5689
|
exports.WysiwygBulletListTool = WysiwygBulletListTool;
|
|
5690
|
+
exports.WysiwygColorExtension = WysiwygColorExtension;
|
|
5482
5691
|
exports.WysiwygEditorInitializeContext = WysiwygEditorInitializeContext;
|
|
5483
5692
|
exports.WysiwygFormatBoldTool = WysiwygFormatBoldTool;
|
|
5484
5693
|
exports.WysiwygFormatItalicTool = WysiwygFormatItalicTool;
|
|
5485
5694
|
exports.WysiwygFormatUnderlineTool = WysiwygFormatUnderlineTool;
|
|
5486
5695
|
exports.WysiwygHistoryTool = WysiwygHistoryTool;
|
|
5487
5696
|
exports.WysiwygLinkTool = WysiwygLinkTool;
|
|
5697
|
+
exports.WysiwygLinter = WysiwygLinter;
|
|
5698
|
+
exports.WysiwygLinterBadWords = WysiwygLinterBadWords;
|
|
5699
|
+
exports.WysiwygLinterHeadingLevel = WysiwygLinterHeadingLevel;
|
|
5700
|
+
exports.WysiwygLinterPlugin = WysiwygLinterPlugin;
|
|
5701
|
+
exports.WysiwygLinterPunctuation = WysiwygLinterPunctuation;
|
|
5488
5702
|
exports.WysiwygOrderedListTool = WysiwygOrderedListTool;
|
|
5489
|
-
exports.WysiwygTextColorTool = WysiwygTextColorTool;
|
|
5490
5703
|
exports.configureDataTableDefaults = configureDataTableDefaults;
|
|
5491
5704
|
exports.createAvatarProps = createAvatarProps;
|
|
5492
5705
|
exports.createCardProps = createCardProps;
|
|
@@ -5500,6 +5713,8 @@ exports.createPaperBaseProps = createPaperBaseProps;
|
|
|
5500
5713
|
exports.createPaperProps = createPaperProps;
|
|
5501
5714
|
exports.createRequiredChipRenderer = createRequiredChipRenderer;
|
|
5502
5715
|
exports.createVFormProps = createVFormProps;
|
|
5716
|
+
exports.createWysiwygColorTool = createWysiwygColorTool;
|
|
5717
|
+
exports.createWysiwygExtension = createWysiwygExtension;
|
|
5503
5718
|
exports.defineFormSelectorComponent = defineFormSelectorComponent;
|
|
5504
5719
|
exports.iconProps = iconProps;
|
|
5505
5720
|
exports.installVuiPlugin = installVuiPlugin;
|