@fishawack/lab-velocity 0.8.5 → 0.8.6

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.
@@ -0,0 +1,114 @@
1
+ @import "element-plus/theme-chalk/el-dropdown";
2
+ @import "element-plus/theme-chalk/el-dropdown-item";
3
+ @import "element-plus/theme-chalk/el-dialog";
4
+ @import "./button.scss";
5
+
6
+ .vel-wysiwyg__controls {
7
+ background-color: $color0;
8
+ display: flex;
9
+ flex-grow: 1;
10
+ border: solid $color5 2px;
11
+ border-bottom: none;
12
+ // margin-bottom: .5 * $spacing;
13
+ font-size: get-ratio(14px);
14
+ padding: 0 .5 * $spacing;
15
+ > * {
16
+ padding: .5 * $spacing;
17
+ padding-right: $spacing;
18
+ --el-font-size-base: get-ratio(14px);
19
+ &:not(:last-child) {
20
+ border-right: solid 1px $color5;
21
+ }
22
+ }
23
+
24
+ button {
25
+ // border: solid 1px $color1;
26
+ background-color: transparent;
27
+ cursor: pointer;
28
+ min-width: 28px;
29
+ padding: 3px 5px;
30
+ line-height: 1;
31
+ &.is-active, &:hover {
32
+ background-color: $color5;
33
+ }
34
+ svg {
35
+ height: 90%;
36
+ }
37
+ }
38
+ .el-dropdown {
39
+ line-height: 1.15;
40
+ }
41
+
42
+ .ql-stroke {
43
+ fill: none;
44
+ stroke: #444;
45
+ stroke-linecap: round;
46
+ stroke-linejoin: round;
47
+ stroke-width: 2;
48
+ }
49
+
50
+ .ql-stroke-miter {
51
+ fill: none;
52
+ stroke: #444;
53
+ stroke-miterlimit: 10;
54
+ stroke-width: 2;
55
+ }
56
+
57
+ .ql-fill,
58
+ .ql-stroke.ql-fill {
59
+ fill: #444;
60
+ }
61
+
62
+ .ql-empty {
63
+ fill: none;
64
+ }
65
+
66
+ .ql-even {
67
+ fill-rule: evenodd;
68
+ }
69
+
70
+ .ql-thin,
71
+ .ql-stroke.ql-thin {
72
+ stroke-width: 1;
73
+ }
74
+
75
+ .ql-transparent {
76
+ opacity: 0.4;
77
+ }
78
+
79
+ ~ div {
80
+ // margin-top: $spacing;
81
+ border: solid $color5 2px;
82
+ padding: 2* $spacing;
83
+ background-color: $color0;
84
+ }
85
+ }
86
+ .vel-wysiwyg__button {
87
+ // border: solid 1px $color1;
88
+ background-color: transparent;
89
+ // cursor: pointer;
90
+
91
+ &.is-active, &:hover {
92
+ background-color: $color5;
93
+ }
94
+ }
95
+
96
+ .vel-wysiwyg {
97
+ // border: solid $color1 1px;
98
+ // padding: $spacing * 1.5;
99
+
100
+ table,td,th {
101
+ border: solid .5px $color1;
102
+ }
103
+ th {
104
+ background-color: $color5;
105
+ }
106
+ hr {
107
+ height: 1px;
108
+ background-color: $color1;
109
+ }
110
+ a {
111
+ text-decoration: underline;
112
+ }
113
+ }
114
+
@@ -0,0 +1,327 @@
1
+ <template>
2
+ <XInput v-bind="$props" class="vel-wysiwyg">
3
+ <template #label>
4
+ <slot name="label" />
5
+ </template>
6
+ <div class="control-group vel-wysiwyg__controls" v-if="editor">
7
+ <el-dropdown>
8
+ Heading
9
+ <template #dropdown>
10
+ <el-dropdown-menu>
11
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
12
+ H1
13
+ </el-dropdown-item>
14
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
15
+ H2
16
+ </el-dropdown-item>
17
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
18
+ H3
19
+ </el-dropdown-item>
20
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
21
+ H4
22
+ </el-dropdown-item>
23
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
24
+ H5
25
+ </el-dropdown-item>
26
+ <el-dropdown-item @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
27
+ H6
28
+ </el-dropdown-item>
29
+ <el-dropdown-item @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
30
+ Paragraph
31
+ </el-dropdown-item>
32
+ </el-dropdown-menu>
33
+ </template>
34
+ </el-dropdown>
35
+ <el-dropdown>
36
+ Style
37
+ <template #dropdown>
38
+ <el-dropdown-menu>
39
+ <el-dropdown-item class="vel-wysiwyg__button" @click="editor.chain().focus().toggleBold().run()" :disabled="!editor.can().chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">Bold</el-dropdown-item>
40
+ <el-dropdown-item class="vel-wysiwyg__button" @click="editor.chain().focus().toggleItalic().run()" :disabled="!editor.can().chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">Italic</el-dropdown-item>
41
+ <el-dropdown-item class="vel-wysiwyg__button" @click="editor.chain().focus().toggleUnderline().run()" :disabled="!editor.can().chain().focus().toggleUnderline().run()" :class="{ 'is-active': editor.isActive('underline') }">Underline</el-dropdown-item>
42
+ </el-dropdown-menu>
43
+ </template>
44
+ </el-dropdown>
45
+ <el-dropdown v-if="table">
46
+ Table
47
+ <template #dropdown>
48
+ <el-dropdown-menu>
49
+ <el-dropdown-item>
50
+ <button @click="editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()">
51
+ Insert table
52
+ </button>
53
+ </el-dropdown-item>
54
+ <el-dropdown-item>
55
+ <button @click="editor.chain().focus().addColumnBefore().run()">
56
+ Add column before
57
+ </button>
58
+ </el-dropdown-item>
59
+ <el-dropdown-item>
60
+ <button @click="editor.chain().focus().addColumnAfter().run()">
61
+ Add column after
62
+ </button>
63
+ </el-dropdown-item>
64
+ <el-dropdown-item>
65
+ <button @click="editor.chain().focus().deleteColumn().run()">
66
+ Delete column
67
+ </button>
68
+ </el-dropdown-item>
69
+ <el-dropdown-item>
70
+ <button @click="editor.chain().focus().addRowBefore().run()">
71
+ Add row before
72
+ </button>
73
+ </el-dropdown-item>
74
+ <el-dropdown-item>
75
+ <button @click="editor.chain().focus().addRowAfter().run()">
76
+ Add row after
77
+ </button>
78
+ </el-dropdown-item>
79
+ <el-dropdown-item>
80
+ <button @click="editor.chain().focus().deleteRow().run()">
81
+ Delete row
82
+ </button>
83
+ </el-dropdown-item>
84
+ <el-dropdown-item>
85
+ <button @click="editor.chain().focus().deleteTable().run()">
86
+ Delete table
87
+ </button>
88
+ </el-dropdown-item>
89
+ <el-dropdown-item>
90
+ <button @click="editor.chain().focus().mergeCells().run()">
91
+ Merge cells
92
+ </button>
93
+ </el-dropdown-item>
94
+ <el-dropdown-item>
95
+ <button @click="editor.chain().focus().splitCell().run()">
96
+ Split cell
97
+ </button>
98
+ </el-dropdown-item>
99
+ <el-dropdown-item>
100
+ <button @click="editor.chain().focus().toggleHeaderColumn().run()">
101
+ Toggle header column
102
+ </button>
103
+ </el-dropdown-item>
104
+ <el-dropdown-item>
105
+ <button @click="editor.chain().focus().toggleHeaderRow().run()">
106
+ Toggle header row
107
+ </button>
108
+ </el-dropdown-item>
109
+ <el-dropdown-item>
110
+ <button @click="editor.chain().focus().toggleHeaderCell().run()">
111
+ Toggle header cell
112
+ </button>
113
+ </el-dropdown-item>
114
+ <el-dropdown-item>
115
+ <button @click="editor.chain().focus().mergeOrSplit().run()">
116
+ Merge or split
117
+ </button>
118
+ </el-dropdown-item>
119
+ <el-dropdown-item>
120
+ <button @click="editor.chain().focus().setCellAttribute('colspan', 2).run()">
121
+ Set cell attribute
122
+ </button>
123
+ </el-dropdown-item>
124
+ <el-dropdown-item>
125
+ <button @click="editor.chain().focus().fixTables().run()">
126
+ Fix tables
127
+ </button>
128
+ </el-dropdown-item>
129
+ <el-dropdown-item>
130
+ <button @click="editor.chain().focus().goToNextCell().run()">
131
+ Go to next cell
132
+ </button>
133
+ </el-dropdown-item>
134
+ <el-dropdown-item>
135
+ <button @click="editor.chain().focus().goToPreviousCell().run()">
136
+ Go to previous cell
137
+ </button>
138
+ </el-dropdown-item>
139
+ </el-dropdown-menu>
140
+ </template>
141
+ </el-dropdown>
142
+ <button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
143
+ <svg viewBox="0 0 18 18"> <line class="ql-stroke" x1="6" x2="15" y1="4" y2="4"></line> <line class="ql-stroke" x1="6" x2="15" y1="9" y2="9"></line> <line class="ql-stroke" x1="6" x2="15" y1="14" y2="14"></line> <line class="ql-stroke" x1="3" x2="3" y1="4" y2="4"></line> <line class="ql-stroke" x1="3" x2="3" y1="9" y2="9"></line> <line class="ql-stroke" x1="3" x2="3" y1="14" y2="14"></line> </svg>
144
+ </button>
145
+ <button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
146
+ <svg viewBox="0 0 18 18"> <line class="ql-stroke" x1="7" x2="15" y1="4" y2="4"></line> <line class="ql-stroke" x1="7" x2="15" y1="9" y2="9"></line> <line class="ql-stroke" x1="7" x2="15" y1="14" y2="14"></line> <line class="ql-stroke ql-thin" x1="2.5" x2="4.5" y1="5.5" y2="5.5"></line> <path class="ql-fill" d="M3.5,6A0.5,0.5,0,0,1,3,5.5V3.085l-0.276.138A0.5,0.5,0,0,1,2.053,3c-0.124-.247-0.023-0.324.224-0.447l1-.5A0.5,0.5,0,0,1,4,2.5v3A0.5,0.5,0,0,1,3.5,6Z"></path> <path class="ql-stroke ql-thin" d="M4.5,10.5h-2c0-.234,1.85-1.076,1.85-2.234A0.959,0.959,0,0,0,2.5,8.156"></path> <path class="ql-stroke ql-thin" d="M2.5,14.846a0.959,0.959,0,0,0,1.85-.109A0.7,0.7,0,0,0,3.75,14a0.688,0.688,0,0,0,.6-0.736,0.959,0.959,0,0,0-1.85-.109"></path> </svg>
147
+ </button>
148
+ <button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
149
+ Code block
150
+ </button>
151
+ <button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
152
+ Blockquote
153
+ </button>
154
+ <button @click="editor.chain().focus().setHorizontalRule().run()">
155
+ Horizontal rule
156
+ </button>
157
+ <button @click="editor.chain().focus().toggleSuperscript().run()" :class="{ 'is-active': editor.isActive('superscript') }">
158
+ <svg viewBox="0 0 18 18"> <path class="ql-fill" d="M15.5,7H13.861a4.015,4.015,0,0,0,1.914-2.975,1.8,1.8,0,0,0-1.6-1.751A1.922,1.922,0,0,0,12.021,3.7a0.5,0.5,0,1,0,.957.291,0.917,0.917,0,0,1,1.053-.725,0.81,0.81,0,0,1,.744.762c0,1.077-1.164,1.925-1.934,2.486A1.423,1.423,0,0,0,12,7.5a0.5,0.5,0,0,0,.5.5h3A0.5,0.5,0,0,0,15.5,7Z"></path> <path class="ql-fill" d="M9.651,5.241a1,1,0,0,0-1.41.108L6,7.964,3.759,5.349a1,1,0,1,0-1.519,1.3L4.683,9.5,2.241,12.35a1,1,0,1,0,1.519,1.3L6,11.036,8.241,13.65a1,1,0,0,0,1.519-1.3L7.317,9.5,9.759,6.651A1,1,0,0,0,9.651,5.241Z"></path> </svg>
159
+ </button>
160
+ <button @click="editor.chain().focus().toggleSubscript().run()" :class="{ 'is-active': editor.isActive('subscript') }">
161
+ <svg viewBox="0 0 18 18"> <path class="ql-fill" d="M15.5,15H13.861a3.858,3.858,0,0,0,1.914-2.975,1.8,1.8,0,0,0-1.6-1.751A1.921,1.921,0,0,0,12.021,11.7a0.50013,0.50013,0,1,0,.957.291h0a0.914,0.914,0,0,1,1.053-.725,0.81,0.81,0,0,1,.744.762c0,1.076-1.16971,1.86982-1.93971,2.43082A1.45639,1.45639,0,0,0,12,15.5a0.5,0.5,0,0,0,.5.5h3A0.5,0.5,0,0,0,15.5,15Z"></path> <path class="ql-fill" d="M9.65,5.241a1,1,0,0,0-1.409.108L6,7.964,3.759,5.349A1,1,0,0,0,2.192,6.59178Q2.21541,6.6213,2.241,6.649L4.684,9.5,2.241,12.35A1,1,0,0,0,3.71,13.70722q0.02557-.02768.049-0.05722L6,11.036,8.241,13.65a1,1,0,1,0,1.567-1.24277Q9.78459,12.3777,9.759,12.35L7.316,9.5,9.759,6.651A1,1,0,0,0,9.65,5.241Z"></path> </svg>
162
+ </button>
163
+ <button @click="setLink" :class="{ 'is-active': editor.isActive('link') }">
164
+ <svg viewBox="0 0 18 18"> <line class="ql-stroke" x1="7" x2="11" y1="7" y2="11"></line> <path class="ql-even ql-stroke" d="M8.9,4.577a3.476,3.476,0,0,1,.36,4.679A3.476,3.476,0,0,1,4.577,8.9C3.185,7.5,2.035,6.4,4.217,4.217S7.5,3.185,8.9,4.577Z"></path> <path class="ql-even ql-stroke" d="M13.423,9.1a3.476,3.476,0,0,0-4.679-.36,3.476,3.476,0,0,0,.36,4.679c1.392,1.392,2.5,2.542,4.679.36S14.815,10.5,13.423,9.1Z"></path> </svg>
165
+ </button>
166
+ </div>
167
+ <editor-content :editor="editor" />
168
+ <el-dialog
169
+ v-model="dialogVisible"
170
+ title="URL"
171
+ width="500"
172
+ >
173
+ <label>Enter URL</label>
174
+ <el-input v-model="newUrl" type="url" />
175
+ <template #footer>
176
+ <div class="dialog-footer">
177
+ <el-button @click="dialogVisible = false">Cancel</el-button>
178
+ <el-button type="primary" @click="updateURL">
179
+ Confirm
180
+ </el-button>
181
+ </div>
182
+ </template>
183
+ </el-dialog>
184
+ </XInput>
185
+ </template>
186
+
187
+ <script>
188
+ import input from "./input.js";
189
+ import XInput from "./input.vue";
190
+ import sanitizeHtml from 'sanitize-html';
191
+ import { ElDropdown, ElDropdownItem, ElDropdownMenu, ElDialog, ElButton, ElInput } from "element-plus";
192
+ import { Editor, EditorContent } from '@tiptap/vue-3'
193
+ import StarterKit from '@tiptap/starter-kit';
194
+ import Underline from '@tiptap/extension-underline'
195
+ import Table from '@tiptap/extension-table'
196
+ import TableCell from '@tiptap/extension-table-cell'
197
+ import TableHeader from '@tiptap/extension-table-header'
198
+ import TableRow from '@tiptap/extension-table-row'
199
+ import Superscript from '@tiptap/extension-superscript'
200
+ import Subscript from '@tiptap/extension-subscript'
201
+ import Link from '@tiptap/extension-link'
202
+
203
+ export default {
204
+ mixins: [input],
205
+
206
+ components: {
207
+ XInput,
208
+ EditorContent,
209
+ ElDropdown,
210
+ ElDropdownItem,
211
+ ElDropdownMenu,
212
+ ElDialog,
213
+ ElButton,
214
+ ElInput
215
+ },
216
+
217
+ props: {
218
+ table: {
219
+ type: Boolean,
220
+ default: false,
221
+ },
222
+ baseClass: {
223
+ type: String,
224
+ default: "vel-wysiwyg",
225
+ },
226
+ },
227
+
228
+ data: () => ({
229
+ editor: null,
230
+ hold: null,
231
+ previousUrl: null,
232
+ newUrl: null,
233
+ dialogVisible:false,
234
+ }),
235
+
236
+ methods: {
237
+ setValue() {
238
+ const temp =
239
+ this.simple && this.modelValue // Surround text in p tags to keep it grouped correctly on simple strings. Ignore if modelValue empty otherwise you'll end up with <p>null</p>
240
+ ? `<p>${this.modelValue}</p>`
241
+ : this.modelValue;
242
+ this.editor.commands.setContent(temp);
243
+
244
+
245
+ },
246
+ // Function to remove p tags from inside li tags, breaks the wysiwyg
247
+ formatCleaner(unformmatted) {
248
+ if(!unformmatted) {
249
+ return "";
250
+ }
251
+ let parser = document.createElement('div');
252
+ parser.innerHTML = unformmatted.replace(/(\r\n|\n|\r|\t)/gm,"");
253
+ const lists = parser.getElementsByTagName('ul');
254
+ for(var x = 0; x < lists.length; x++) {
255
+ lists[x].innerHTML = sanitizeHtml(lists[x].innerHTML, {
256
+ allowedTags: [ 'b', 'i', 'em', 'strong', 'a','li']
257
+ });
258
+ }
259
+ return parser.innerHTML;
260
+ },
261
+ setLink() {
262
+ this.previousUrl = this.editor.getAttributes('link').href;
263
+ this.newUrl = this.previousUrl;
264
+ this.dialogVisible = true;
265
+
266
+ },
267
+ updateURL() {
268
+ // cancelled
269
+ this.dialogVisible = false;
270
+ let url = this.newUrl;
271
+ if (url === this.previousUrl) {
272
+ return
273
+ }
274
+
275
+ // empty
276
+ if (url === '') {
277
+ this.editor
278
+ .chain()
279
+ .focus()
280
+ .extendMarkRange('link')
281
+ .unsetLink()
282
+ .run()
283
+
284
+ return
285
+ }
286
+ // update link
287
+ this.editor
288
+ .chain()
289
+ .focus()
290
+ .extendMarkRange('link')
291
+ .setLink({ href: url })
292
+ .run()
293
+ }
294
+ },
295
+
296
+ mounted() {
297
+ let extensions = [
298
+ StarterKit,
299
+ Underline,
300
+ Superscript,
301
+ Subscript,
302
+ Link.configure({
303
+ openOnClick: false,
304
+ defaultProtocol: 'https',
305
+ })
306
+ ];
307
+ if(this.$props.table) {
308
+ extensions.push(
309
+ Table.configure({
310
+ resizable: true,
311
+ }),
312
+ TableRow,
313
+ TableHeader,
314
+ TableCell);
315
+ }
316
+
317
+ this.editor = new Editor({
318
+ extensions: extensions,
319
+ });
320
+ this.setValue();
321
+
322
+ this.editor.on('blur', ({ editor, event }) => {
323
+ this.$emit("update:modelValue", event.srcElement.innerHTML);
324
+ })
325
+ },
326
+ };
327
+ </script>
package/general.scss CHANGED
@@ -13,6 +13,7 @@
13
13
  @import "./components/_link.scss";
14
14
  @import "./components/_cascader.scss";
15
15
  @import "./components/_wysiwyg.scss";
16
+ @import "./components/_wysiwyg2.scss";
16
17
  @import "./components/_upload.scss";
17
18
  @import "./components/_inputNumber.scss";
18
19
 
package/index.js CHANGED
@@ -10,6 +10,7 @@ export { default as file } from "./form/file.vue";
10
10
  export { default as Select } from "./form/Select.vue";
11
11
  export { default as Switch } from "./form/Switch.vue";
12
12
  export { default as Wysiwyg } from "./form/Wysiwyg.vue";
13
+ export { default as Wysiwyg2 } from "./form/Wysiwyg2.vue";
13
14
  export { default as Upload } from "./form/Upload.vue";
14
15
  export { default as InputNumber } from "./form/InputNumber.vue";
15
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishawack/lab-velocity",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "description": "Avalere Health branded style system",
5
5
  "scripts": {
6
6
  "setup": "npm ci || npm i && npm run content",
@@ -40,6 +40,17 @@
40
40
  "vuex-persistedstate": "^4.1.0"
41
41
  },
42
42
  "dependencies": {
43
+ "@tiptap/extension-link": "^2.11.2",
44
+ "@tiptap/extension-subscript": "^2.11.2",
45
+ "@tiptap/extension-superscript": "^2.11.2",
46
+ "@tiptap/extension-table": "^2.11.2",
47
+ "@tiptap/extension-table-cell": "^2.11.2",
48
+ "@tiptap/extension-table-header": "^2.11.2",
49
+ "@tiptap/extension-table-row": "^2.11.2",
50
+ "@tiptap/extension-underline": "^2.11.2",
51
+ "@tiptap/pm": "^2.11.2",
52
+ "@tiptap/starter-kit": "^2.11.2",
53
+ "@tiptap/vue-3": "^2.11.2",
43
54
  "element-plus": "^2.7.8",
44
55
  "quill": "^1.3.7",
45
56
  "sanitize-html": "^2.13.1"