@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.mjs
CHANGED
|
@@ -8,14 +8,14 @@ import { getDocumentScroller as getDocumentScroller$1 } from '@fastkit/vue-scrol
|
|
|
8
8
|
import { VProgressCircular } from '@fastkit/vue-loading';
|
|
9
9
|
export * from '@fastkit/vue-loading';
|
|
10
10
|
import { useScopeColorClass, colorSchemeProps, useColorClasses, toScopeColorClass } from '@fastkit/vue-color-scheme';
|
|
11
|
-
import { loadImage, IN_WINDOW, isPromise
|
|
11
|
+
import { loadImage, IN_WINDOW, isPromise } from '@fastkit/helpers';
|
|
12
12
|
export { ICON_NAMES } from '@fastkit/icon-font';
|
|
13
13
|
import { VAppContainer, VAppLayoutControl } from '@fastkit/vue-app-layout';
|
|
14
14
|
import { createTextableProps, createTextableEmits, TextableControl } from '@fastkit/vue-form-control';
|
|
15
15
|
import { useEditor, EditorContent, BubbleMenu } from '@tiptap/vue-3';
|
|
16
16
|
import StarterKit from '@tiptap/starter-kit';
|
|
17
17
|
import { Extension } from '@tiptap/core';
|
|
18
|
-
import {
|
|
18
|
+
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
19
19
|
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
|
20
20
|
import { BulletList } from '@tiptap/extension-bullet-list';
|
|
21
21
|
import { Bold } from '@tiptap/extension-bold';
|
|
@@ -25,6 +25,7 @@ import { History } from '@tiptap/extension-history';
|
|
|
25
25
|
import { Link } from '@tiptap/extension-link';
|
|
26
26
|
import { validateIf, url } from '@fastkit/rules';
|
|
27
27
|
import { OrderedList } from '@tiptap/extension-ordered-list';
|
|
28
|
+
import TextStyle from '@tiptap/extension-text-style';
|
|
28
29
|
|
|
29
30
|
const CONTROL_SIZES = ['sm', 'md', 'lg'];
|
|
30
31
|
const CONTROL_FIELD_VARIANTS = ['outlined', 'filled', 'flat'];
|
|
@@ -1227,6 +1228,7 @@ const VButtonGroup = defineComponent({
|
|
|
1227
1228
|
|
|
1228
1229
|
setup(props, ctx) {
|
|
1229
1230
|
return () => {
|
|
1231
|
+
let hasIcon = false;
|
|
1230
1232
|
let buttonLength = 0;
|
|
1231
1233
|
let tmp = renderSlotOrEmpty$1(ctx.slots) || [];
|
|
1232
1234
|
|
|
@@ -1243,6 +1245,11 @@ const VButtonGroup = defineComponent({
|
|
|
1243
1245
|
}
|
|
1244
1246
|
|
|
1245
1247
|
buttonLength++;
|
|
1248
|
+
|
|
1249
|
+
if (!hasIcon && node.props && !!node.props.icon) {
|
|
1250
|
+
hasIcon = true;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1246
1253
|
return {
|
|
1247
1254
|
isButton: true,
|
|
1248
1255
|
node
|
|
@@ -1259,6 +1266,7 @@ const VButtonGroup = defineComponent({
|
|
|
1259
1266
|
...childProps,
|
|
1260
1267
|
rouded: false,
|
|
1261
1268
|
class: ['v-button-group__item', {
|
|
1269
|
+
'v-button--icon': hasIcon,
|
|
1262
1270
|
'v-button-group__item--has-left': hasLeft,
|
|
1263
1271
|
'v-button-group__item--has-right': hasRight
|
|
1264
1272
|
}]
|
|
@@ -1268,7 +1276,9 @@ const VButtonGroup = defineComponent({
|
|
|
1268
1276
|
return child.node;
|
|
1269
1277
|
});
|
|
1270
1278
|
return createVNode("div", {
|
|
1271
|
-
"class":
|
|
1279
|
+
"class": ['v-button-group', {
|
|
1280
|
+
'v-button-group--has-icon': hasIcon
|
|
1281
|
+
}]
|
|
1272
1282
|
}, [$children]);
|
|
1273
1283
|
};
|
|
1274
1284
|
}
|
|
@@ -2887,7 +2897,12 @@ const prefixedEventName = (source) => {
|
|
|
2887
2897
|
};
|
|
2888
2898
|
class WysiwygEditorInitializeContext {
|
|
2889
2899
|
listeners = {};
|
|
2890
|
-
|
|
2900
|
+
_vui;
|
|
2901
|
+
get vui() {
|
|
2902
|
+
return this._vui();
|
|
2903
|
+
}
|
|
2904
|
+
constructor(vuiGetter, opts = {}) {
|
|
2905
|
+
this._vui = vuiGetter;
|
|
2891
2906
|
EDITOR_EVENTS.forEach((event) => {
|
|
2892
2907
|
this.listeners[event] = [];
|
|
2893
2908
|
const prefixed = prefixedEventName(event);
|
|
@@ -2916,7 +2931,44 @@ class WysiwygEditorInitializeContext {
|
|
|
2916
2931
|
return opts;
|
|
2917
2932
|
}
|
|
2918
2933
|
}
|
|
2934
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2935
|
+
// extension: Extension<Options, Storage>,
|
|
2936
|
+
// ): Extension<Options, Storage>;
|
|
2937
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2938
|
+
// node: Node<Options, Storage>,
|
|
2939
|
+
// ): Node<Options, Storage>;
|
|
2940
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2941
|
+
// mark: Mark<Options, Storage>,
|
|
2942
|
+
// ): Mark<Options, Storage>;
|
|
2943
|
+
// export function createWysiwygExtension<Options = any, Storage = any>(
|
|
2944
|
+
// factory: WysiwygExtensionFactory<Options, Storage>,
|
|
2945
|
+
// ): WysiwygExtensionFactory<Options, Storage>;
|
|
2946
|
+
function isCreatedWysiwygExtension(source) {
|
|
2947
|
+
return (!!source &&
|
|
2948
|
+
typeof source === 'object' &&
|
|
2949
|
+
source.__isCreatedWysiwygExtension === true);
|
|
2950
|
+
}
|
|
2951
|
+
function createWysiwygExtension(extension) {
|
|
2952
|
+
const ext = {
|
|
2953
|
+
__isCreatedWysiwygExtension: true,
|
|
2954
|
+
_configs: [],
|
|
2955
|
+
configure: (opts) => {
|
|
2956
|
+
opts && ext._configs.push(opts);
|
|
2957
|
+
return ext;
|
|
2958
|
+
},
|
|
2959
|
+
raw: extension,
|
|
2960
|
+
};
|
|
2961
|
+
return ext;
|
|
2962
|
+
}
|
|
2919
2963
|
function resolveRawWysiwygExtension(raw, ctx) {
|
|
2964
|
+
if (isCreatedWysiwygExtension(raw)) {
|
|
2965
|
+
const { raw: _raw, _configs } = raw;
|
|
2966
|
+
let ext = typeof _raw === 'function' ? _raw(ctx) : _raw;
|
|
2967
|
+
_configs.forEach((config) => {
|
|
2968
|
+
ext = ext.configure(config);
|
|
2969
|
+
});
|
|
2970
|
+
return ext;
|
|
2971
|
+
}
|
|
2920
2972
|
return typeof raw === 'function' ? raw(ctx) : raw;
|
|
2921
2973
|
}
|
|
2922
2974
|
function resolveRawWysiwygExtensions(raws, ctx) {
|
|
@@ -2985,7 +3037,7 @@ const VWysiwygEditor = defineComponent({
|
|
|
2985
3037
|
nodeType: VUI_WYSIWYG_EDITOR_SYMBOL,
|
|
2986
3038
|
validationValue: () => textRef.value
|
|
2987
3039
|
});
|
|
2988
|
-
const initializeCtx = new WysiwygEditorInitializeContext({
|
|
3040
|
+
const initializeCtx = new WysiwygEditorInitializeContext(() => vui, {
|
|
2989
3041
|
onCreate: ({
|
|
2990
3042
|
editor
|
|
2991
3043
|
}) => {
|
|
@@ -3084,9 +3136,9 @@ const VWysiwygEditor = defineComponent({
|
|
|
3084
3136
|
const _editor = editor.value;
|
|
3085
3137
|
const variant = vui.setting(bubbleMenu ? 'containedVariant' : 'plainVariant');
|
|
3086
3138
|
return createVNode(VButtonGroup, {
|
|
3087
|
-
"class": {
|
|
3139
|
+
"class": ['v-wysiwyg-editor__toolbar', {
|
|
3088
3140
|
'v-wysiwyg-editor__floating-toolbar': props.floatingToolbar
|
|
3089
|
-
},
|
|
3141
|
+
}],
|
|
3090
3142
|
"variant": variant
|
|
3091
3143
|
}, _isSlot$7(_slot = tools.map(({
|
|
3092
3144
|
key,
|
|
@@ -3098,16 +3150,23 @@ const VWysiwygEditor = defineComponent({
|
|
|
3098
3150
|
const isActive = !!_editor && resolveContextableValue(context, active);
|
|
3099
3151
|
const isDisabled = !inputControl.canOperation || !!_editor && resolveContextableValue(context, disabled);
|
|
3100
3152
|
let iconName;
|
|
3153
|
+
let child;
|
|
3101
3154
|
|
|
3102
3155
|
if (typeof icon === 'function') {
|
|
3103
3156
|
if (_editor) {
|
|
3104
|
-
|
|
3157
|
+
const _child = icon(context);
|
|
3158
|
+
|
|
3159
|
+
if (typeof _child === 'function') {
|
|
3160
|
+
child = _child();
|
|
3161
|
+
} else {
|
|
3162
|
+
iconName = child;
|
|
3163
|
+
}
|
|
3105
3164
|
}
|
|
3106
3165
|
} else {
|
|
3107
3166
|
iconName = icon;
|
|
3108
3167
|
}
|
|
3109
3168
|
|
|
3110
|
-
if (!iconName) return;
|
|
3169
|
+
if (!iconName && child == null) return;
|
|
3111
3170
|
return createVNode(VButton, {
|
|
3112
3171
|
"tabindex": -1,
|
|
3113
3172
|
"key": key,
|
|
@@ -3115,7 +3174,9 @@ const VWysiwygEditor = defineComponent({
|
|
|
3115
3174
|
"onClick": ev => onClick(context, ev),
|
|
3116
3175
|
"color": isActive ? toolButtonActiveColor : undefined,
|
|
3117
3176
|
"disabled": isDisabled
|
|
3118
|
-
},
|
|
3177
|
+
}, _isSlot$7(child) ? child : {
|
|
3178
|
+
default: () => [child]
|
|
3179
|
+
});
|
|
3119
3180
|
})) ? _slot : {
|
|
3120
3181
|
default: () => [_slot]
|
|
3121
3182
|
});
|
|
@@ -3199,190 +3260,223 @@ function resolveContextableValue(ctx, source) {
|
|
|
3199
3260
|
return typeof source === 'function' ? source(ctx) : source;
|
|
3200
3261
|
}
|
|
3201
3262
|
|
|
3202
|
-
const PROBLEM_CLASS_NAME = 'v-linter__problem';
|
|
3203
|
-
const ISSUE_ICON_CLASS_NAME = 'v-linter__issue-icon';
|
|
3204
|
-
const
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
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
|
-
|
|
3263
|
+
const PROBLEM_CLASS_NAME = 'v-linter__problem';
|
|
3264
|
+
const ISSUE_ICON_CLASS_NAME = 'v-linter__issue-icon';
|
|
3265
|
+
const ISSUE_DATASET_NAME = 'data-issue-id';
|
|
3266
|
+
|
|
3267
|
+
function resolveWysiwygLinterFixMessage(message) {
|
|
3268
|
+
return typeof message === 'function' ? message() : message;
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
function renderIcon(view, issue) {
|
|
3272
|
+
const {
|
|
3273
|
+
level = 'warning'
|
|
3274
|
+
} = issue;
|
|
3275
|
+
const icon = document.createElement('div');
|
|
3276
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3277
|
+
icon.className = `${ISSUE_ICON_CLASS_NAME} ${level}-scope`;
|
|
3278
|
+
icon.setAttribute(ISSUE_DATASET_NAME, issue.id);
|
|
3279
|
+
|
|
3280
|
+
if (typeof message === 'string') {
|
|
3281
|
+
icon.title = message;
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
return icon;
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
function runAllLinterPlugins(doc, plugins) {
|
|
3288
|
+
const decorations = [];
|
|
3289
|
+
const issues = plugins.map(RegisteredLinterPlugin => {
|
|
3290
|
+
return new RegisteredLinterPlugin(doc).scan().getResults();
|
|
3291
|
+
}).flat();
|
|
3292
|
+
issues.forEach(issue => {
|
|
3293
|
+
const {
|
|
3294
|
+
level = 'warning',
|
|
3295
|
+
icon
|
|
3296
|
+
} = issue;
|
|
3297
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3298
|
+
decorations.push(Decoration.inline(issue.from, issue.to, {
|
|
3299
|
+
class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
|
|
3300
|
+
'data-issue-id': issue.id,
|
|
3301
|
+
title: typeof message === 'string' ? message : undefined
|
|
3302
|
+
}));
|
|
3303
|
+
|
|
3304
|
+
if (icon) {
|
|
3305
|
+
decorations.push(Decoration.widget(issue.from, view => renderIcon(view, issue)));
|
|
3306
|
+
}
|
|
3307
|
+
});
|
|
3308
|
+
const decorationSet = DecorationSet.create(doc, decorations);
|
|
3309
|
+
return {
|
|
3310
|
+
issues,
|
|
3311
|
+
decorationSet
|
|
3312
|
+
};
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
const WysiwygLinter = createWysiwygExtension(ctx => {
|
|
3316
|
+
function showMenu(view, issue, event) {
|
|
3317
|
+
const message = resolveWysiwygLinterFixMessage(issue.message);
|
|
3318
|
+
const variant = ctx.vui.setting('containedVariant');
|
|
3319
|
+
const scope = ctx.vui.setting(`${issue.level}Scope`);
|
|
3320
|
+
return ctx.vui.menu({
|
|
3321
|
+
activator: event,
|
|
3322
|
+
content: stack => createVNode("div", {
|
|
3323
|
+
"class": "v-linter__issue-menu__body"
|
|
3324
|
+
}, [createVNode("div", {
|
|
3325
|
+
"class": ['v-linter__issue-menu__message', `${scope}-scope ${variant}`]
|
|
3326
|
+
}, [message]), issue.fix.length && createVNode("div", {
|
|
3327
|
+
"class": "v-linter__issue-menu__fixers"
|
|
3328
|
+
}, [issue.fix.map((fixer, index) => createVNode("div", {
|
|
3329
|
+
"key": index,
|
|
3330
|
+
"class": "v-linter__issue-menu__fixer"
|
|
3331
|
+
}, [createVNode("button", {
|
|
3332
|
+
"type": "button",
|
|
3333
|
+
"class": "v-linter__issue-menu__fixer__button",
|
|
3334
|
+
"onClick": () => {
|
|
3335
|
+
stack.close();
|
|
3336
|
+
fixer.handler(view, issue);
|
|
3337
|
+
}
|
|
3338
|
+
}, [createVNode("span", {
|
|
3339
|
+
"class": "v-linter__issue-menu__fixer__button__message"
|
|
3340
|
+
}, [resolveWysiwygLinterFixMessage(fixer.message)])])]))])])
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
return Extension.create({
|
|
3345
|
+
name: 'linter',
|
|
3346
|
+
|
|
3347
|
+
addOptions() {
|
|
3348
|
+
return {
|
|
3349
|
+
plugins: []
|
|
3350
|
+
};
|
|
3351
|
+
},
|
|
3352
|
+
|
|
3353
|
+
addStorage() {
|
|
3354
|
+
return {
|
|
3355
|
+
issues: []
|
|
3356
|
+
};
|
|
3357
|
+
},
|
|
3358
|
+
|
|
3359
|
+
addProseMirrorPlugins() {
|
|
3360
|
+
const {
|
|
3361
|
+
plugins
|
|
3362
|
+
} = this.options;
|
|
3363
|
+
const {
|
|
3364
|
+
storage
|
|
3365
|
+
} = this;
|
|
3366
|
+
|
|
3367
|
+
const runAll = doc => {
|
|
3368
|
+
const {
|
|
3369
|
+
issues,
|
|
3370
|
+
decorationSet
|
|
3371
|
+
} = runAllLinterPlugins(doc, plugins);
|
|
3372
|
+
storage.issues = issues;
|
|
3373
|
+
return decorationSet;
|
|
3374
|
+
};
|
|
3375
|
+
|
|
3376
|
+
const getIssue = id => storage.issues.find(issue => issue.id === id);
|
|
3377
|
+
|
|
3378
|
+
const getIssueElementByEvent = source => {
|
|
3379
|
+
if (!source || !(source instanceof HTMLElement)) {
|
|
3380
|
+
return;
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
const issueId = source.getAttribute(ISSUE_DATASET_NAME);
|
|
3384
|
+
const issue = issueId && getIssue(issueId);
|
|
3385
|
+
if (!issue) return;
|
|
3386
|
+
return {
|
|
3387
|
+
issue
|
|
3388
|
+
};
|
|
3389
|
+
};
|
|
3390
|
+
|
|
3391
|
+
return [new Plugin({
|
|
3392
|
+
key: new PluginKey('linter'),
|
|
3393
|
+
state: {
|
|
3394
|
+
init(_, {
|
|
3395
|
+
doc
|
|
3396
|
+
}) {
|
|
3397
|
+
return runAll(doc);
|
|
3398
|
+
},
|
|
3399
|
+
|
|
3400
|
+
apply(transaction, oldState) {
|
|
3401
|
+
return transaction.docChanged ? runAll(transaction.doc) : oldState;
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
},
|
|
3405
|
+
props: {
|
|
3406
|
+
decorations(state) {
|
|
3407
|
+
return this.getState(state);
|
|
3408
|
+
},
|
|
3409
|
+
|
|
3410
|
+
handleClick(view, _, event) {
|
|
3411
|
+
const info = getIssueElementByEvent(event.target);
|
|
3412
|
+
|
|
3413
|
+
if (!info) {
|
|
3414
|
+
return false;
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3417
|
+
const {
|
|
3418
|
+
issue
|
|
3419
|
+
} = info;
|
|
3420
|
+
const {
|
|
3421
|
+
from,
|
|
3422
|
+
to
|
|
3423
|
+
} = issue;
|
|
3424
|
+
|
|
3425
|
+
const focus = () => view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to)).scrollIntoView());
|
|
3426
|
+
|
|
3427
|
+
focus();
|
|
3428
|
+
showMenu(view, issue, event);
|
|
3429
|
+
return true;
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
}
|
|
3433
|
+
})];
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
});
|
|
3437
|
+
});
|
|
3438
|
+
|
|
3439
|
+
let IDX = 256, BUFFER;
|
|
3440
|
+
const HEX = [];
|
|
3441
|
+
while (IDX--)
|
|
3442
|
+
HEX[IDX] = (IDX + 256).toString(16).substring(1);
|
|
3443
|
+
function cheepUUID() {
|
|
3444
|
+
let i = 0, num, out = '';
|
|
3445
|
+
if (!BUFFER || IDX + 16 > 256) {
|
|
3446
|
+
BUFFER = Array((i = 256));
|
|
3447
|
+
while (i--)
|
|
3448
|
+
BUFFER[i] = (256 * Math.random()) | 0;
|
|
3449
|
+
i = IDX = 0;
|
|
3240
3450
|
}
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3451
|
+
for (; i < 16; i++) {
|
|
3452
|
+
num = BUFFER[IDX + i];
|
|
3453
|
+
if (i == 6)
|
|
3454
|
+
out += HEX[(num & 15) | 64];
|
|
3455
|
+
else if (i == 8)
|
|
3456
|
+
out += HEX[(num & 63) | 128];
|
|
3457
|
+
else
|
|
3458
|
+
out += HEX[num];
|
|
3459
|
+
if (i & 1 && i > 1 && i < 11)
|
|
3460
|
+
out += '-';
|
|
3244
3461
|
}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
}
|
|
3249
|
-
function getMenuElement(source) {
|
|
3250
|
-
return getIssueElement(source, ISSUE_MENU_CLASS_NAME);
|
|
3251
|
-
}
|
|
3252
|
-
function getProblemElement(source) {
|
|
3253
|
-
return getIssueElement(source, PROBLEM_CLASS_NAME);
|
|
3254
|
-
}
|
|
3255
|
-
function runAllLinterPlugins(doc, plugins) {
|
|
3256
|
-
const decorations = [];
|
|
3257
|
-
const results = plugins
|
|
3258
|
-
.map((RegisteredLinterPlugin) => {
|
|
3259
|
-
return new RegisteredLinterPlugin(doc).scan().getResults();
|
|
3260
|
-
})
|
|
3261
|
-
.flat();
|
|
3262
|
-
results.forEach((issue) => {
|
|
3263
|
-
const { level = 'warning' } = issue;
|
|
3264
|
-
decorations.push(Decoration.inline(issue.from, issue.to, {
|
|
3265
|
-
class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
|
|
3266
|
-
'data-issue': JSON.stringify(issue),
|
|
3267
|
-
title: issue.message,
|
|
3268
|
-
}), Decoration.widget(issue.from, (view) => renderIcon(view, issue)), Decoration.widget(issue.from, (view) => renderMenu(view, issue)));
|
|
3269
|
-
});
|
|
3270
|
-
return DecorationSet.create(doc, decorations);
|
|
3271
|
-
}
|
|
3272
|
-
function updateMenusPosition(editorElement) {
|
|
3273
|
-
const { left, right } = editorElement.getBoundingClientRect();
|
|
3274
|
-
const menus = Array.from(editorElement.querySelectorAll(`.${ISSUE_MENU_CLASS_NAME}`));
|
|
3275
|
-
menus.forEach((menu) => {
|
|
3276
|
-
const { left: menuLeft, right: menuRight } = menu.getBoundingClientRect();
|
|
3277
|
-
const overflow = menuRight - right;
|
|
3278
|
-
let offset = 0;
|
|
3279
|
-
if (overflow > 0) {
|
|
3280
|
-
offset = -overflow;
|
|
3281
|
-
if (menuLeft + offset < left) {
|
|
3282
|
-
offset = 0;
|
|
3283
|
-
}
|
|
3284
|
-
}
|
|
3285
|
-
menu.style.transform = `translateX(${offset}px)`;
|
|
3286
|
-
});
|
|
3287
|
-
}
|
|
3288
|
-
const debouncedUpdateMenusPosition = debounce(updateMenusPosition, 250);
|
|
3289
|
-
const Linter = Extension.create({
|
|
3290
|
-
name: 'linter',
|
|
3291
|
-
addOptions() {
|
|
3292
|
-
return {
|
|
3293
|
-
plugins: [],
|
|
3294
|
-
};
|
|
3295
|
-
},
|
|
3296
|
-
onCreate() {
|
|
3297
|
-
const { dom } = this.editor.view;
|
|
3298
|
-
debouncedUpdateMenusPosition(dom);
|
|
3299
|
-
},
|
|
3300
|
-
onUpdate() {
|
|
3301
|
-
const { dom } = this.editor.view;
|
|
3302
|
-
debouncedUpdateMenusPosition(dom);
|
|
3303
|
-
},
|
|
3304
|
-
addProseMirrorPlugins() {
|
|
3305
|
-
const { plugins } = this.options;
|
|
3306
|
-
return [
|
|
3307
|
-
new Plugin({
|
|
3308
|
-
key: new PluginKey('linter'),
|
|
3309
|
-
state: {
|
|
3310
|
-
init(_, { doc }) {
|
|
3311
|
-
return runAllLinterPlugins(doc, plugins);
|
|
3312
|
-
},
|
|
3313
|
-
apply(transaction, oldState) {
|
|
3314
|
-
return transaction.docChanged
|
|
3315
|
-
? runAllLinterPlugins(transaction.doc, plugins)
|
|
3316
|
-
: oldState;
|
|
3317
|
-
},
|
|
3318
|
-
},
|
|
3319
|
-
props: {
|
|
3320
|
-
decorations(state) {
|
|
3321
|
-
return this.getState(state);
|
|
3322
|
-
},
|
|
3323
|
-
handleClick(view, _, event) {
|
|
3324
|
-
const activeMenus = Array.from(view.dom.querySelectorAll(`.${ISSUE_MENU_CLASS_NAME}--active`));
|
|
3325
|
-
activeMenus.forEach((menu) => menu.classList.remove(`${ISSUE_MENU_CLASS_NAME}--active`));
|
|
3326
|
-
const problem = getProblemElement(event.target);
|
|
3327
|
-
const issueString = problem && problem.dataset['issue'];
|
|
3328
|
-
const issue = issueString && JSON.parse(issueString);
|
|
3329
|
-
if (issue) {
|
|
3330
|
-
const menuWrapper = problem.previousElementSibling;
|
|
3331
|
-
const menu = menuWrapper &&
|
|
3332
|
-
menuWrapper.querySelector(`.${ISSUE_MENU_CLASS_NAME}`);
|
|
3333
|
-
menu && menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3334
|
-
const { from, to } = issue;
|
|
3335
|
-
view.dispatch(view.state.tr
|
|
3336
|
-
.setSelection(TextSelection.create(view.state.doc, from, to))
|
|
3337
|
-
.scrollIntoView());
|
|
3338
|
-
return true;
|
|
3339
|
-
}
|
|
3340
|
-
const menu = getMenuElement(event.target);
|
|
3341
|
-
if (menu) {
|
|
3342
|
-
menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3343
|
-
}
|
|
3344
|
-
const target = getIconElement(event.target);
|
|
3345
|
-
if (target && target.issue) {
|
|
3346
|
-
const menuWrapper = target.nextElementSibling;
|
|
3347
|
-
const menu = menuWrapper &&
|
|
3348
|
-
menuWrapper.querySelector(`.${ISSUE_MENU_CLASS_NAME}`);
|
|
3349
|
-
menu && menu.classList.add(`${ISSUE_MENU_CLASS_NAME}--active`);
|
|
3350
|
-
const { from, to } = target.issue;
|
|
3351
|
-
view.dispatch(view.state.tr
|
|
3352
|
-
.setSelection(TextSelection.create(view.state.doc, from, to))
|
|
3353
|
-
.scrollIntoView());
|
|
3354
|
-
return true;
|
|
3355
|
-
}
|
|
3356
|
-
return false;
|
|
3357
|
-
},
|
|
3358
|
-
handleDoubleClick(view, _, event) {
|
|
3359
|
-
const target = getIconElement(event.target);
|
|
3360
|
-
if (target && target.issue) {
|
|
3361
|
-
const prob = target.issue;
|
|
3362
|
-
if (prob.fix) {
|
|
3363
|
-
prob.fix(view, prob);
|
|
3364
|
-
view.focus();
|
|
3365
|
-
return true;
|
|
3366
|
-
}
|
|
3367
|
-
}
|
|
3368
|
-
return false;
|
|
3369
|
-
},
|
|
3370
|
-
},
|
|
3371
|
-
}),
|
|
3372
|
-
];
|
|
3373
|
-
},
|
|
3374
|
-
});
|
|
3462
|
+
IDX++;
|
|
3463
|
+
return out;
|
|
3464
|
+
}
|
|
3375
3465
|
|
|
3376
|
-
class
|
|
3466
|
+
class WysiwygLinterPlugin {
|
|
3377
3467
|
doc;
|
|
3378
3468
|
results = [];
|
|
3379
3469
|
constructor(doc) {
|
|
3380
3470
|
this.doc = doc;
|
|
3381
3471
|
}
|
|
3382
3472
|
record(result) {
|
|
3473
|
+
const { fix = [], icon = false } = result;
|
|
3383
3474
|
this.results.push({
|
|
3384
3475
|
level: 'error',
|
|
3476
|
+
id: cheepUUID(),
|
|
3385
3477
|
...result,
|
|
3478
|
+
fix: Array.isArray(fix) ? fix : [fix],
|
|
3479
|
+
icon,
|
|
3386
3480
|
});
|
|
3387
3481
|
}
|
|
3388
3482
|
scan() {
|
|
@@ -3393,35 +3487,45 @@ class LinterPlugin {
|
|
|
3393
3487
|
}
|
|
3394
3488
|
}
|
|
3395
3489
|
|
|
3396
|
-
function
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
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: () => createVNode("span", null, [createVNode("code", null, [fixValue]), 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
|
+
};
|
|
3422
3526
|
}
|
|
3423
3527
|
|
|
3424
|
-
class
|
|
3528
|
+
class WysiwygLinterHeadingLevel extends WysiwygLinterPlugin {
|
|
3425
3529
|
fixHeader(level) {
|
|
3426
3530
|
return function ({ state, dispatch }, issue) {
|
|
3427
3531
|
dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level }));
|
|
@@ -3438,7 +3542,10 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3438
3542
|
message: `Heading too small (${level} under ${lastHeadLevel})`,
|
|
3439
3543
|
from: position + 1,
|
|
3440
3544
|
to: position + 1 + node.content.size,
|
|
3441
|
-
fix:
|
|
3545
|
+
fix: {
|
|
3546
|
+
message: '修正する',
|
|
3547
|
+
handler: this.fixHeader(lastHeadLevel + 1),
|
|
3548
|
+
},
|
|
3442
3549
|
});
|
|
3443
3550
|
}
|
|
3444
3551
|
lastHeadLevel = level;
|
|
@@ -3448,7 +3555,7 @@ class HeadingLevel extends LinterPlugin {
|
|
|
3448
3555
|
}
|
|
3449
3556
|
}
|
|
3450
3557
|
|
|
3451
|
-
class
|
|
3558
|
+
class WysiwygLinterPunctuation extends WysiwygLinterPlugin {
|
|
3452
3559
|
regex = / ([,.!?:]) ?/g;
|
|
3453
3560
|
fix(replacement) {
|
|
3454
3561
|
return function ({ state, dispatch }, issue) {
|
|
@@ -3469,7 +3576,10 @@ class Punctuation extends LinterPlugin {
|
|
|
3469
3576
|
message: 'Suspicious spacing around punctuation',
|
|
3470
3577
|
from: position + matches.index,
|
|
3471
3578
|
to: position + matches.index + matches[0].length,
|
|
3472
|
-
fix:
|
|
3579
|
+
fix: {
|
|
3580
|
+
message: 'Fix it!!!',
|
|
3581
|
+
handler: this.fix(`${matches[1]} `),
|
|
3582
|
+
},
|
|
3473
3583
|
});
|
|
3474
3584
|
}
|
|
3475
3585
|
});
|
|
@@ -3477,6 +3587,49 @@ class Punctuation extends LinterPlugin {
|
|
|
3477
3587
|
}
|
|
3478
3588
|
}
|
|
3479
3589
|
|
|
3590
|
+
const WysiwygColorExtension = 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
|
+
|
|
3480
3633
|
const WysiwygBulletListTool = (vui, options) => {
|
|
3481
3634
|
const tool = {
|
|
3482
3635
|
key: 'bulletList',
|
|
@@ -3617,18 +3770,73 @@ const WysiwygOrderedListTool = (vui, options) => {
|
|
|
3617
3770
|
return tool;
|
|
3618
3771
|
};
|
|
3619
3772
|
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
};
|
|
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 createVNode("span", {
|
|
3786
|
+
"class": "v-wysiwyg-color-tool__button"
|
|
3787
|
+
}, [createVNode(VIcon, {
|
|
3788
|
+
"class": "v-wysiwyg-color-tool__button__icon",
|
|
3789
|
+
"name": vui.icon('editorTextColor')
|
|
3790
|
+
}, null), 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 => 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) => 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
|
+
}, [createVNode("span", {
|
|
3823
|
+
"class": "v-wysiwyg-color-tool__item__color",
|
|
3824
|
+
"style": item.color ? {
|
|
3825
|
+
color: item.color
|
|
3826
|
+
} : {}
|
|
3827
|
+
}, null), opts.withLabel && createVNode("span", {
|
|
3828
|
+
"class": "v-wysiwyg-color-tool__item__name"
|
|
3829
|
+
}, [item.name])]))])
|
|
3830
|
+
});
|
|
3831
|
+
},
|
|
3832
|
+
floating: true,
|
|
3833
|
+
extensions: [TextStyle, WysiwygColorExtension]
|
|
3834
|
+
};
|
|
3835
|
+
return tool;
|
|
3836
|
+
};
|
|
3837
|
+
|
|
3838
|
+
return WysiwygColorTool;
|
|
3839
|
+
}
|
|
3632
3840
|
|
|
3633
3841
|
const {
|
|
3634
3842
|
props,
|
|
@@ -5245,6 +5453,10 @@ class VuiService {
|
|
|
5245
5453
|
return this.stack.snackbar(...args);
|
|
5246
5454
|
}
|
|
5247
5455
|
|
|
5456
|
+
menu(...args) {
|
|
5457
|
+
return this.stack.menu(...args);
|
|
5458
|
+
}
|
|
5459
|
+
|
|
5248
5460
|
formPrompt(settings, slot) {
|
|
5249
5461
|
let form;
|
|
5250
5462
|
const options = {
|
|
@@ -5396,4 +5608,4 @@ function installVuiPlugin(app, opts) {
|
|
|
5396
5608
|
return app.use(VuiPlugin, opts);
|
|
5397
5609
|
}
|
|
5398
5610
|
|
|
5399
|
-
export { AVATAR_SIZES,
|
|
5611
|
+
export { AVATAR_SIZES, CHIP_SIZES, CONTROL_FIELD_VARIANTS, CONTROL_LOADING_SPINNER_SIZES, CONTROL_SIZES, PAGINATION_ALIGNS, VApp, VAvatar, VBreadcrumbs, VBusyImage, VButton, VButtonGroup, VCard, VCardActions, VCardContent, VCheckbox, VCheckboxGroup, VChip, VContentSwitcher, VDataTable, VDrawerLayout, VForm, VFormControl, VGridContainer, VGridItem, VHero, VIcon, VListTile, VNavigation, VNavigationItem, VNumberField, VOption, VOptionGroup, VPagination, VPaper, VRadio, VRadioGroup, VSelect, VSkeltonLoaderBone, VSwitch, VSwitchGroup, VTabs, VTextField, VTextarea, VToolbar, VToolbarEdge, VToolbarMenu, VToolbarTitle, VUI_CHECKBOX_GROUP_SYMBOL, VUI_CHECKBOX_SYMBOL, VUI_FORM_SYMBOL, VUI_OPTION_SYMBOL, VUI_RADIO_GROUP_SYMBOL, VUI_RADIO_SYMBOL, VUI_SELECT_SYMBOL, VUI_SWITCH_GROUP_SYMBOL, VUI_SWITCH_SYMBOL, VUI_TEXTAREA_SYMBOL, VUI_TEXT_FIELD_SYMBOL, VUI_WYSIWYG_EDITOR_SYMBOL, VWysiwygEditor, VuiColorProviderInjectionKey, VuiControlFieldInjectionKey, VuiControlInjectionKey, VuiInjectionKey, VuiPlugin, VuiService, WysiwygBulletListTool, WysiwygColorExtension, WysiwygEditorInitializeContext, WysiwygFormatBoldTool, WysiwygFormatItalicTool, WysiwygFormatUnderlineTool, WysiwygHistoryTool, WysiwygLinkTool, WysiwygLinter, WysiwygLinterBadWords, WysiwygLinterHeadingLevel, WysiwygLinterPlugin, WysiwygLinterPunctuation, WysiwygOrderedListTool, configureDataTableDefaults, createAvatarProps, createCardProps, createChipProps, createControlFieldProviderProps, createControlProps, createElevationProps, createListTileProps, createNavigationItemProps, createPaperBaseProps, createPaperProps, createRequiredChipRenderer, createVFormProps, createWysiwygColorTool, createWysiwygExtension, defineFormSelectorComponent, iconProps, installVuiPlugin, listTileEmits, mergeVuiPluginOptions, mergeVuiServiceIconSettings, mergeVuiServiceOptions, mergeVuiServiceUISettings, paginationProps, rawIconProp, renderNavigationItemInput, resolveNavigationItemInput, resolveRawIconProp, resolveRawWysiwygEditorTools, resolveRawWysiwygExtensions, splitAttrs, useControl, useControlField, useElevation, useVui, useVuiColorProvider, vueButtonProps };
|