@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.
Files changed (36) hide show
  1. package/dist/tool/index.js +1 -0
  2. package/dist/tool/vite-plugin.d.ts.map +1 -1
  3. package/dist/vui.cjs.js +443 -228
  4. package/dist/vui.cjs.prod.js +443 -228
  5. package/dist/vui.css +166 -12
  6. package/dist/vui.d.ts +103 -54
  7. package/dist/vui.min.css +1 -1
  8. package/dist/vui.min.css.map +1 -1
  9. package/dist/vui.mjs +437 -225
  10. package/package.json +7 -6
  11. package/src/components/VButton/VButtonGroup.scss +4 -0
  12. package/src/components/VButton/VButtonGroup.tsx +12 -1
  13. package/src/components/VWysiwygEditor/VWysiwygEditor.scss +4 -0
  14. package/src/components/VWysiwygEditor/VWysiwygEditor.tsx +19 -9
  15. package/src/components/VWysiwygEditor/extensions/.DS_Store +0 -0
  16. package/src/components/VWysiwygEditor/extensions/color.ts +72 -0
  17. package/src/components/VWysiwygEditor/extensions/index.ts +1 -0
  18. package/src/components/VWysiwygEditor/extensions/linter/.DS_Store +0 -0
  19. package/src/components/VWysiwygEditor/extensions/linter/Linter.scss +80 -15
  20. package/src/components/VWysiwygEditor/extensions/linter/Linter.tsx +214 -0
  21. package/src/components/VWysiwygEditor/extensions/linter/LinterPlugin.ts +32 -11
  22. package/src/components/VWysiwygEditor/extensions/linter/index.ts +3 -3
  23. package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.tsx +50 -0
  24. package/src/components/VWysiwygEditor/extensions/linter/plugins/HeadingLevel.ts +9 -3
  25. package/src/components/VWysiwygEditor/extensions/linter/plugins/Punctuation.ts +9 -3
  26. package/src/components/VWysiwygEditor/extensions/linter/plugins/index.ts +3 -3
  27. package/src/components/VWysiwygEditor/extensions/linter/utils.ts +28 -0
  28. package/src/components/VWysiwygEditor/schemes.ts +87 -5
  29. package/src/components/VWysiwygEditor/tools/color.scss +140 -0
  30. package/src/components/VWysiwygEditor/tools/color.tsx +90 -0
  31. package/src/components/VWysiwygEditor/tools/index.ts +1 -1
  32. package/src/service.tsx +5 -0
  33. package/src/tool/vite-plugin.ts +1 -0
  34. package/src/components/VWysiwygEditor/extensions/linter/Linter.ts +0 -262
  35. package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.ts +0 -34
  36. package/src/components/VWysiwygEditor/tools/text-color.ts +0 -14
@@ -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": "v-button-group"
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
- constructor(opts = {}) {
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
- iconName = icon(context);
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
- }, null);
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 ISSUE_MENU_CLASS_NAME = 'v-linter__issue-menu';
3210
- function renderIcon(view, issue) {
3211
- const { level = 'warning' } = issue;
3212
- const icon = document.createElement('div');
3213
- icon.className = `${ISSUE_ICON_CLASS_NAME} ${level}-scope`;
3214
- icon.title = issue.message;
3215
- icon.issue = issue;
3216
- return icon;
3217
- }
3218
- function renderMenu(view, issue) {
3219
- const menuWrapper = document.createElement('div');
3220
- menuWrapper.className = 'v-linter__issue-menu-wrapper';
3221
- const menu = document.createElement('div');
3222
- menu.className = `${ISSUE_MENU_CLASS_NAME} elevation-3`;
3223
- menu.innerText = issue.message;
3224
- const { fix, fixMessage } = issue;
3225
- if (fix && fixMessage) {
3226
- const $fix = document.createElement('button');
3227
- $fix.type = 'button';
3228
- $fix.innerHTML = fixMessage;
3229
- $fix.addEventListener('click', () => {
3230
- fix(view, issue);
3231
- });
3232
- $fix.className = `v-linter__issue-menu__fix`;
3233
- menu.appendChild($fix);
3234
- }
3235
- menu.issue = issue;
3236
- menuWrapper.appendChild(menu);
3237
- return menuWrapper;
3238
- }
3239
- function getIssueElement(source, className) {
3240
- if (!source || !(source instanceof HTMLElement)) {
3241
- return;
3242
- }
3243
- if (source.classList.contains(className)) {
3244
- return source;
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
- const el = source.closest(`.${className}`);
3247
- if (el) {
3248
- return el;
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
- function getIconElement(source) {
3252
- return getIssueElement(source, ISSUE_ICON_CLASS_NAME);
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 LinterPlugin {
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 BadWords(words) {
3402
- const regex = new RegExp(`\\b(${words.join('|')})\\b`);
3403
- return class BadWords extends LinterPlugin {
3404
- scan() {
3405
- this.doc.descendants((node, position) => {
3406
- if (!node.isText) {
3407
- return;
3408
- }
3409
- const matches = regex.exec(node.text);
3410
- if (matches) {
3411
- const fixValue = matches[0] + '!!!!!';
3412
- this.record({
3413
- level: 'warning',
3414
- message: `Try not to say '${matches[0]}'`,
3415
- from: position + matches.index,
3416
- to: position + matches.index + matches[0].length,
3417
- fix: () => {
3418
- console.log('hoge');
3419
- },
3420
- fixMessage: `「${fixValue}」に修正する。`,
3421
- });
3422
- }
3423
- });
3424
- return this;
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 HeadingLevel extends LinterPlugin {
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: this.fixHeader(lastHeadLevel + 1),
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 Punctuation extends LinterPlugin {
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: this.fix(`${matches[1]} `),
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
- const WysiwygTextColorTool = (vui) => {
3626
- const tool = {
3627
- key: 'textColor',
3628
- icon: vui.icon('editorTextColor'),
3629
- // icon: (gen) => vui.icon('editorTextColor'),
3630
- onClick: (ctx) => {
3631
- ctx.vui.alert('ok');
3632
- },
3633
- floating: true,
3634
- };
3635
- return tool;
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;