@fastkit/vui 0.12.9 → 0.12.10

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 (33) hide show
  1. package/dist/vui.css +138 -409
  2. package/dist/vui.css.map +1 -1
  3. package/dist/vui.d.ts +97 -409
  4. package/dist/vui.mjs +167 -1125
  5. package/dist/vui.mjs.map +1 -1
  6. package/package.json +18 -40
  7. package/src/components/index.ts +3 -1
  8. package/src/injections.ts +1 -1
  9. package/src/components/VWysiwygEditor/VWysiwygEditor.scss +0 -68
  10. package/src/components/VWysiwygEditor/VWysiwygEditor.tsx +0 -354
  11. package/src/components/VWysiwygEditor/extensions/color.ts +0 -72
  12. package/src/components/VWysiwygEditor/extensions/index.ts +0 -2
  13. package/src/components/VWysiwygEditor/extensions/linter/Linter.scss +0 -139
  14. package/src/components/VWysiwygEditor/extensions/linter/Linter.tsx +0 -210
  15. package/src/components/VWysiwygEditor/extensions/linter/LinterPlugin.ts +0 -65
  16. package/src/components/VWysiwygEditor/extensions/linter/index.ts +0 -5
  17. package/src/components/VWysiwygEditor/extensions/linter/plugins/BadWords.tsx +0 -50
  18. package/src/components/VWysiwygEditor/extensions/linter/plugins/HeadingLevel.ts +0 -39
  19. package/src/components/VWysiwygEditor/extensions/linter/plugins/Punctuation.ts +0 -49
  20. package/src/components/VWysiwygEditor/extensions/linter/plugins/index.ts +0 -3
  21. package/src/components/VWysiwygEditor/extensions/linter/utils.ts +0 -28
  22. package/src/components/VWysiwygEditor/index.ts +0 -4
  23. package/src/components/VWysiwygEditor/schemes.ts +0 -251
  24. package/src/components/VWysiwygEditor/tools/bullet-list.ts +0 -18
  25. package/src/components/VWysiwygEditor/tools/color.scss +0 -134
  26. package/src/components/VWysiwygEditor/tools/color.tsx +0 -90
  27. package/src/components/VWysiwygEditor/tools/format-bold.ts +0 -19
  28. package/src/components/VWysiwygEditor/tools/format-italic.ts +0 -18
  29. package/src/components/VWysiwygEditor/tools/format-underline.ts +0 -18
  30. package/src/components/VWysiwygEditor/tools/history.ts +0 -26
  31. package/src/components/VWysiwygEditor/tools/index.ts +0 -8
  32. package/src/components/VWysiwygEditor/tools/link.ts +0 -57
  33. package/src/components/VWysiwygEditor/tools/ordered-list.ts +0 -21
@@ -1,139 +0,0 @@
1
- @layer vui {
2
- .v-linter {
3
- &__problem {
4
- margin-bottom: -1px;
5
- cursor: help;
6
- background: var(--deep-color);
7
- border-bottom: 1px solid var(--main-color);
8
- }
9
-
10
- &__issue-icon {
11
- position: absolute;
12
- right: 2px;
13
- display: inline-flex;
14
- align-items: center;
15
- justify-content: center;
16
- width: 1.2em;
17
- height: 1.2em;
18
- margin-top: 0.2em;
19
- // padding-left: 0.5px;
20
- font-family: times, georgia, serif;
21
- font-size: 15px;
22
- font-weight: 700;
23
- line-height: 1;
24
- color: var(--text-color);
25
- text-align: center;
26
- cursor: pointer;
27
- background: var(--main-color);
28
- border-radius: 100px;
29
-
30
- &::before {
31
- content: '!';
32
- }
33
- }
34
-
35
- &__issue-menu-wrapper {
36
- position: relative;
37
- display: inline-block;
38
- width: 0px;
39
- height: 1em;
40
- overflow: visible;
41
- }
42
-
43
- &__issue-menu {
44
- font-size: 87.5%;
45
- // font-size: 12px;
46
- line-height: 1.5;
47
-
48
- .v-dialog__body {
49
- padding: 0;
50
- font-size: inherit;
51
- }
52
-
53
- &__message {
54
- padding: 8px;
55
- }
56
-
57
- &__fixers {
58
- position: relative;
59
- padding: 4px 0;
60
- // padding: 8px;
61
- // border-top: solid 1px var(--divider-color);
62
- &::before {
63
- position: absolute;
64
- top: 0;
65
- right: 0;
66
- left: 0;
67
- display: block;
68
- height: 1px;
69
- content: '';
70
- background: currentColor;
71
- opacity: 0.5;
72
- }
73
- }
74
-
75
- &__fixer {
76
- &__button {
77
- position: relative;
78
- display: block;
79
- width: 100%;
80
- padding: 8px;
81
- font: inherit;
82
- font-size: 12px;
83
- // margin-top: 8px;
84
- // color: var(--palette-link);
85
- text-align: left;
86
- // text-decoration: underline;
87
- cursor: pointer;
88
- background: transparent;
89
- border: 0;
90
- outline: 0;
91
- appearance: none;
92
-
93
- &::before {
94
- position: absolute;
95
- inset: 0;
96
- display: block;
97
- content: '';
98
- background: currentColor;
99
- opacity: 0;
100
- transition: 0.15s;
101
- }
102
-
103
- &:hover,
104
- &:focus {
105
- &::before {
106
- opacity: 0.1;
107
- }
108
- }
109
-
110
- &__message {
111
- position: relative;
112
- }
113
- }
114
- }
115
- // pointer-events: none;
116
- // background: #fff;
117
- // border-radius: 4px;
118
- // opacity: 0;
119
- // transition: opacity 0.15s;
120
-
121
- // &--active {
122
- // pointer-events: auto;
123
- // opacity: 1;
124
- // }
125
-
126
- &__fix {
127
- display: inline;
128
- margin-top: 8px;
129
- color: var(--palette-link);
130
- text-decoration: underline;
131
- cursor: pointer;
132
- background: transparent;
133
- border: 0;
134
- outline: 0;
135
- appearance: none;
136
- }
137
- }
138
- }
139
- }
@@ -1,210 +0,0 @@
1
- import './Linter.scss';
2
-
3
- import { Extension } from '@tiptap/core';
4
- import { Decoration, DecorationSet } from 'prosemirror-view';
5
- import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
6
- import { Node as ProsemirrorNode } from 'prosemirror-model';
7
- import {
8
- WysiwygLinterPlugin,
9
- WysiwygLinterResult as Issue,
10
- WysiwygLinterFixMessage,
11
- } from './LinterPlugin';
12
- import { EditorView } from 'prosemirror-view';
13
- import { createWysiwygExtension } from '../../schemes';
14
-
15
- const PROBLEM_CLASS_NAME = 'v-linter__problem';
16
- const ISSUE_ICON_CLASS_NAME = 'v-linter__issue-icon';
17
- const ISSUE_DATASET_NAME = 'data-issue-id';
18
-
19
- function resolveWysiwygLinterFixMessage(message: WysiwygLinterFixMessage) {
20
- return typeof message === 'function' ? message() : message;
21
- }
22
-
23
- function renderIcon(view: EditorView, issue: Issue) {
24
- const { level = 'warning' } = issue;
25
- const icon = document.createElement('div');
26
- const message = resolveWysiwygLinterFixMessage(issue.message);
27
-
28
- icon.className = `${ISSUE_ICON_CLASS_NAME} ${level}-scope`;
29
- icon.setAttribute(ISSUE_DATASET_NAME, issue.id);
30
-
31
- if (typeof message === 'string') {
32
- icon.title = message;
33
- }
34
-
35
- return icon;
36
- }
37
-
38
- function runAllLinterPlugins(
39
- doc: ProsemirrorNode,
40
- plugins: Array<typeof WysiwygLinterPlugin>,
41
- ) {
42
- const decorations: [any?] = [];
43
-
44
- const issues = plugins
45
- .map((RegisteredLinterPlugin) => {
46
- return new RegisteredLinterPlugin(doc).scan().getResults();
47
- })
48
- .flat();
49
-
50
- issues.forEach((issue) => {
51
- const { level = 'warning', icon } = issue;
52
- const message = resolveWysiwygLinterFixMessage(issue.message);
53
- decorations.push(
54
- Decoration.inline(issue.from, issue.to, {
55
- class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
56
- 'data-issue-id': issue.id,
57
- title: typeof message === 'string' ? message : undefined,
58
- }),
59
- );
60
- if (icon) {
61
- decorations.push(
62
- Decoration.widget(issue.from, (view) => renderIcon(view, issue)),
63
- );
64
- }
65
- });
66
-
67
- const decorationSet = DecorationSet.create(doc, decorations);
68
-
69
- return {
70
- issues,
71
- decorationSet,
72
- };
73
- }
74
-
75
- export interface WysiwygLinterOptions {
76
- plugins: Array<typeof WysiwygLinterPlugin>;
77
- }
78
-
79
- export interface WysiwygLinterStorage {
80
- issues: Issue[];
81
- }
82
-
83
- export const WysiwygLinter = createWysiwygExtension((ctx) => {
84
- function showMenu(view: EditorView, issue: Issue, event: Event) {
85
- const message = resolveWysiwygLinterFixMessage(issue.message);
86
- const variant = ctx.vui.setting('containedVariant');
87
- const scope = ctx.vui.setting(`${issue.level}Scope`);
88
-
89
- return ctx.vui.menu({
90
- activator: event,
91
- content: (stack) => (
92
- <div class="v-linter__issue-menu__body">
93
- <div
94
- class={[
95
- 'v-linter__issue-menu__message',
96
- `${scope}-scope ${variant}`,
97
- ]}>
98
- {message}
99
- </div>
100
- {issue.fix.length && (
101
- <div class="v-linter__issue-menu__fixers">
102
- {issue.fix.map((fixer, index) => (
103
- <div key={index} class="v-linter__issue-menu__fixer">
104
- <button
105
- type="button"
106
- class="v-linter__issue-menu__fixer__button"
107
- onClick={() => {
108
- stack.close();
109
- fixer.handler(view, issue);
110
- }}>
111
- <span class="v-linter__issue-menu__fixer__button__message">
112
- {resolveWysiwygLinterFixMessage(fixer.message)}
113
- </span>
114
- </button>
115
- </div>
116
- ))}
117
- </div>
118
- )}
119
- </div>
120
- ),
121
- });
122
- }
123
-
124
- return Extension.create<WysiwygLinterOptions, WysiwygLinterStorage>({
125
- name: 'linter',
126
-
127
- addOptions() {
128
- return {
129
- plugins: [],
130
- };
131
- },
132
- addStorage() {
133
- return {
134
- issues: [],
135
- };
136
- },
137
- addProseMirrorPlugins() {
138
- const { plugins } = this.options;
139
- const { storage } = this;
140
-
141
- const runAll = (doc: ProsemirrorNode) => {
142
- const { issues, decorationSet } = runAllLinterPlugins(doc, plugins);
143
- storage.issues = issues;
144
- return decorationSet;
145
- };
146
-
147
- const getIssue = (id: string) =>
148
- storage.issues.find((issue) => issue.id === id);
149
-
150
- const getIssueElementByEvent = (
151
- source: EventTarget | null,
152
- ):
153
- | {
154
- issue: Issue;
155
- }
156
- | undefined => {
157
- if (!source || !(source instanceof HTMLElement)) {
158
- return;
159
- }
160
- const issueId = source.getAttribute(ISSUE_DATASET_NAME);
161
- const issue = issueId && getIssue(issueId);
162
- if (!issue) return;
163
-
164
- return {
165
- issue,
166
- };
167
- };
168
-
169
- const linterPlugin: Plugin<any> = new Plugin({
170
- key: new PluginKey('linter'),
171
- state: {
172
- init(_, { doc }) {
173
- return runAll(doc);
174
- },
175
- apply(transaction, oldState) {
176
- return transaction.docChanged ? runAll(transaction.doc) : oldState;
177
- },
178
- },
179
- props: {
180
- decorations(state) {
181
- return linterPlugin.getState(state);
182
- },
183
- handleClick(view, _, event) {
184
- const info = getIssueElementByEvent(event.target);
185
- if (!info) {
186
- return false;
187
- }
188
-
189
- const { issue } = info;
190
- const { from, to } = issue;
191
-
192
- const focus = () =>
193
- view.dispatch(
194
- view.state.tr
195
- .setSelection(TextSelection.create(view.state.doc, from, to))
196
- .scrollIntoView(),
197
- );
198
-
199
- focus();
200
-
201
- showMenu(view, issue, event);
202
- return true;
203
- },
204
- },
205
- });
206
-
207
- return [linterPlugin];
208
- },
209
- });
210
- });
@@ -1,65 +0,0 @@
1
- import { VNodeChild } from 'vue';
2
- import { Node as ProsemirrorNode } from 'prosemirror-model';
3
- import { EditorView } from 'prosemirror-view';
4
- import { cheepUUID } from './utils';
5
-
6
- export type WysiwygLinterFixFn = (
7
- view: EditorView,
8
- issue: WysiwygLinterResult,
9
- ) => any;
10
-
11
- export type WysiwygLinterFixMessage = string | (() => VNodeChild);
12
-
13
- export interface WysiwygLinterFixer {
14
- message: WysiwygLinterFixMessage;
15
- handler: WysiwygLinterFixFn;
16
- }
17
-
18
- export type WysiwygLinterResultLevel = 'warning' | 'error';
19
-
20
- // fixers
21
- export interface WysiwygLinterResult {
22
- id: string;
23
- icon: boolean;
24
- level: WysiwygLinterResultLevel;
25
- message: WysiwygLinterFixMessage;
26
- from: number;
27
- to: number;
28
- fix: WysiwygLinterFixer[];
29
- }
30
-
31
- export interface RawLinterResult
32
- extends Omit<WysiwygLinterResult, 'level' | 'fix' | 'id' | 'icon'> {
33
- level?: WysiwygLinterResultLevel;
34
- icon?: boolean;
35
- fix?: WysiwygLinterFixer | WysiwygLinterFixer[];
36
- }
37
-
38
- export class WysiwygLinterPlugin {
39
- protected doc: ProsemirrorNode;
40
-
41
- private results: Array<WysiwygLinterResult> = [];
42
-
43
- constructor(doc: ProsemirrorNode) {
44
- this.doc = doc;
45
- }
46
-
47
- record(result: RawLinterResult) {
48
- const { fix = [], icon = false } = result;
49
- this.results.push({
50
- level: 'error',
51
- id: cheepUUID(),
52
- ...result,
53
- fix: Array.isArray(fix) ? fix : [fix],
54
- icon,
55
- });
56
- }
57
-
58
- scan() {
59
- return this;
60
- }
61
-
62
- getResults() {
63
- return this.results;
64
- }
65
- }
@@ -1,5 +0,0 @@
1
- export { WysiwygLinter } from './Linter';
2
- export { WysiwygLinterPlugin } from './LinterPlugin';
3
- export type { WysiwygLinterOptions } from './Linter';
4
-
5
- export * from './plugins';
@@ -1,50 +0,0 @@
1
- import { WysiwygLinterPlugin } from '../LinterPlugin';
2
-
3
- export function WysiwygLinterBadWords(
4
- words: string[],
5
- ): typeof WysiwygLinterPlugin {
6
- const regex = new RegExp(`\\b(${words.join('|')})\\b`);
7
-
8
- return class WysiwygLinterBadWords extends WysiwygLinterPlugin {
9
- scan() {
10
- this.doc.descendants((node: any, position: number) => {
11
- if (!node.isText) {
12
- return;
13
- }
14
-
15
- const matches = regex.exec(node.text);
16
-
17
- if (matches) {
18
- const fixValue = matches[0] + '!!!!!';
19
-
20
- this.record({
21
- level: 'warning',
22
- message: `Try not to say '${matches[0]}'`,
23
- from: position + matches.index,
24
- to: position + matches.index + matches[0].length,
25
- fix: [
26
- {
27
- message: () => (
28
- <span>
29
- <code>{fixValue}</code>に修正する。
30
- </span>
31
- ),
32
- handler: () => {
33
- console.log('hoge');
34
- },
35
- },
36
- {
37
- message: 'どうにかする',
38
- handler: () => {
39
- console.log('hoge');
40
- },
41
- },
42
- ],
43
- });
44
- }
45
- });
46
-
47
- return this;
48
- }
49
- };
50
- }
@@ -1,39 +0,0 @@
1
- import { EditorView } from 'prosemirror-view';
2
- import {
3
- WysiwygLinterPlugin,
4
- WysiwygLinterResult as Issue,
5
- } from '../LinterPlugin';
6
-
7
- export class WysiwygLinterHeadingLevel extends WysiwygLinterPlugin {
8
- fixHeader(level: number) {
9
- return function ({ state, dispatch }: EditorView, issue: Issue) {
10
- dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level }));
11
- };
12
- }
13
-
14
- scan() {
15
- let lastHeadLevel: number | null = null;
16
-
17
- this.doc.descendants((node, position) => {
18
- if (node.type.name === 'heading') {
19
- // Check whether heading levels fit under the current level
20
- const { level } = node.attrs;
21
-
22
- if (lastHeadLevel != null && level > lastHeadLevel + 1) {
23
- this.record({
24
- message: `Heading too small (${level} under ${lastHeadLevel})`,
25
- from: position + 1,
26
- to: position + 1 + node.content.size,
27
- fix: {
28
- message: '修正する',
29
- handler: this.fixHeader(lastHeadLevel + 1),
30
- },
31
- });
32
- }
33
- lastHeadLevel = level;
34
- }
35
- });
36
-
37
- return this;
38
- }
39
- }
@@ -1,49 +0,0 @@
1
- import { EditorView } from 'prosemirror-view';
2
- import {
3
- WysiwygLinterPlugin,
4
- WysiwygLinterResult as Issue,
5
- } from '../LinterPlugin';
6
-
7
- export class WysiwygLinterPunctuation extends WysiwygLinterPlugin {
8
- public regex = / ([,.!?:]) ?/g;
9
-
10
- fix(replacement: any) {
11
- return function ({ state, dispatch }: EditorView, issue: Issue) {
12
- dispatch(
13
- state.tr.replaceWith(
14
- issue.from,
15
- issue.to,
16
- state.schema.text(replacement),
17
- ),
18
- );
19
- };
20
- }
21
-
22
- scan() {
23
- this.doc.descendants((node, position) => {
24
- if (!node.isText) {
25
- return;
26
- }
27
-
28
- if (!node.text) {
29
- return;
30
- }
31
-
32
- const matches = this.regex.exec(node.text);
33
-
34
- if (matches) {
35
- this.record({
36
- message: 'Suspicious spacing around punctuation',
37
- from: position + matches.index,
38
- to: position + matches.index + matches[0].length,
39
- fix: {
40
- message: 'Fix it!!!',
41
- handler: this.fix(`${matches[1]} `),
42
- },
43
- });
44
- }
45
- });
46
-
47
- return this;
48
- }
49
- }
@@ -1,3 +0,0 @@
1
- export * from './BadWords';
2
- export * from './HeadingLevel';
3
- export * from './Punctuation';
@@ -1,28 +0,0 @@
1
- let IDX = 256,
2
- BUFFER: any;
3
- const HEX: any = [];
4
- while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
5
-
6
- export function cheepUUID() {
7
- let i = 0,
8
- num,
9
- out = '';
10
-
11
- if (!BUFFER || IDX + 16 > 256) {
12
- BUFFER = Array((i = 256));
13
- while (i--) BUFFER[i] = (256 * Math.random()) | 0;
14
- i = IDX = 0;
15
- }
16
-
17
- for (; i < 16; i++) {
18
- num = BUFFER[IDX + i];
19
- if (i == 6) out += HEX[(num & 15) | 64];
20
- else if (i == 8) out += HEX[(num & 63) | 128];
21
- else out += HEX[num];
22
-
23
- if (i & 1 && i > 1 && i < 11) out += '-';
24
- }
25
-
26
- IDX++;
27
- return out;
28
- }
@@ -1,4 +0,0 @@
1
- export * from './VWysiwygEditor';
2
- export * from './extensions';
3
- export * from './tools';
4
- export * from './schemes';