@kungal/editor-nuxt 0.13.0 → 0.15.0
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/CHANGELOG.md +72 -0
- package/nuxt.config.ts +16 -10
- package/package.json +4 -3
- package/runtime/KunEditorToolbar.vue +45 -16
- package/runtime/KunEditorViewSwitch.vue +36 -0
- package/tailwind.css +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# @kungal/editor-nuxt
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a7273bb: Ship `tailwind.css` so the KunUI toolbar/picker/tabs styles render drop-in.
|
|
8
|
+
|
|
9
|
+
`<KunEditorToolbar>` / `<KunEditorViewSwitch>` use Tailwind utility classes
|
|
10
|
+
(grids, aspect, sizes, dividers, menu items). Tailwind v4 doesn't scan
|
|
11
|
+
`node_modules`, so without registration the sticker/emoji grid collapsed (huge
|
|
12
|
+
stickers). The package now ships `tailwind.css` containing a path-relative
|
|
13
|
+
`@source "./runtime"` — the Tailwind-team-recommended pattern for a
|
|
14
|
+
Tailwind-based library, and pnpm-layout-safe (resolved relative to the file, not
|
|
15
|
+
the app's `node_modules`). Consumers add one line to their Tailwind entry:
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
@import "@kungal/ui-vue/style.css";
|
|
19
|
+
@import "@kungal/editor-nuxt/tailwind.css";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- a7273bb: Toolbar: headings become one "text size" dropdown; remove the formula button.
|
|
23
|
+
|
|
24
|
+
- **Headings → a single "text size" control** (Paragraph / H1–H6) instead of
|
|
25
|
+
three H1/H2/H3 buttons — the modern standard, and it can set Paragraph (reset),
|
|
26
|
+
which the old toggle buttons couldn't. The headless `EditorToolbar` uses a
|
|
27
|
+
native `<select>` (new `.kun-editor__heading-select` class hook); the KunUI
|
|
28
|
+
`<KunEditorToolbar>` uses a `<KunPopover>` with each level shown at its own size
|
|
29
|
+
(like the forum). Both drive `setHeadingCommand`.
|
|
30
|
+
- **Remove the math/formula button.** With no selection it inserted an empty
|
|
31
|
+
inline-math node (a broken formula box). Math is entered via the existing
|
|
32
|
+
`$…$` / `$$` input rules instead — the ecosystem norm (prosemirror-math). The
|
|
33
|
+
spoiler button stays.
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies [a7273bb]
|
|
38
|
+
- Updated dependencies [a7273bb]
|
|
39
|
+
- @kungal/editor-core@0.15.0
|
|
40
|
+
- @kungal/editor-vue@0.15.0
|
|
41
|
+
|
|
42
|
+
## 0.14.0
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- 506813b: Add a `#view-switch` slot and a KunUI view switch — the Preview/Markdown tabs are
|
|
47
|
+
now a swappable layer too.
|
|
48
|
+
|
|
49
|
+
`<KunEditor>` exposes a `#view-switch` scoped slot whose props are
|
|
50
|
+
`KunEditorViewSwitchApi` (`mode` / `setMode` / `labels`). The hand-rolled tabs
|
|
51
|
+
are the slot's fallback — omit the slot and nothing changes. This lets a host
|
|
52
|
+
render a real component (or anything) for the view switch and drive the editor
|
|
53
|
+
via `setMode`, without reaching into internals.
|
|
54
|
+
|
|
55
|
+
`@kungal/editor-nuxt` ships `<KunEditorViewSwitch>` (auto-imported): the tabs as a
|
|
56
|
+
real `<KunTab variant="underlined">` (keyboard nav, sliding indicator, a11y):
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<KunEditor v-model="md">
|
|
60
|
+
<template #view-switch="s"><KunEditorViewSwitch v-bind="s" /></template>
|
|
61
|
+
<template #toolbar="api"><KunEditorToolbar v-bind="api" /></template>
|
|
62
|
+
</KunEditor>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Same "headless core + optional KunUI layer" pattern as `#toolbar` /
|
|
66
|
+
`<KunEditorToolbar>`: `@kungal/editor-vue` stays UI-kit-free (default tabs), the
|
|
67
|
+
KunUI ecosystem gets native chrome. Exports `KunEditorViewSwitchApi`.
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- Updated dependencies [506813b]
|
|
72
|
+
- @kungal/editor-vue@0.14.0
|
|
73
|
+
- @kungal/editor-core@0.14.0
|
|
74
|
+
|
|
3
75
|
## 0.13.0
|
|
4
76
|
|
|
5
77
|
### Minor Changes
|
package/nuxt.config.ts
CHANGED
|
@@ -5,10 +5,12 @@ import { defineNuxtModule, addComponent, createResolver } from '@nuxt/kit'
|
|
|
5
5
|
// downstream templates use `<KunEditor>` with no import (and Nuxt generates its
|
|
6
6
|
// types, keeping the tag type-checked in consumer templates).
|
|
7
7
|
//
|
|
8
|
-
// It also ships
|
|
9
|
-
// #toolbar
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// It also ships the KunUI chrome for <KunEditor>'s slots — <KunEditorToolbar>
|
|
9
|
+
// (#toolbar) and <KunEditorViewSwitch> (#view-switch, the Preview/Markdown tabs
|
|
10
|
+
// as a real <KunTab>). They belong HERE (this layer already assumes
|
|
11
|
+
// @kungal/ui-nuxt), not in headless @kungal/editor-vue — so editor-vue stays
|
|
12
|
+
// UI-kit-free while the KunUI ecosystem gets native chrome. Same shape as
|
|
13
|
+
// TipTap's optional UI package.
|
|
12
14
|
export default defineNuxtConfig({
|
|
13
15
|
modules: [
|
|
14
16
|
defineNuxtModule({
|
|
@@ -24,6 +26,10 @@ export default defineNuxtConfig({
|
|
|
24
26
|
name: 'KunEditorToolbar',
|
|
25
27
|
filePath: resolve('./runtime/KunEditorToolbar.vue')
|
|
26
28
|
})
|
|
29
|
+
addComponent({
|
|
30
|
+
name: 'KunEditorViewSwitch',
|
|
31
|
+
filePath: resolve('./runtime/KunEditorViewSwitch.vue')
|
|
32
|
+
})
|
|
27
33
|
}
|
|
28
34
|
})
|
|
29
35
|
],
|
|
@@ -58,9 +64,9 @@ export default defineNuxtConfig({
|
|
|
58
64
|
}
|
|
59
65
|
})
|
|
60
66
|
|
|
61
|
-
// NOTE: this layer
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
+
// NOTE: this layer assumes @kungal/ui-nuxt is already extended (its components
|
|
68
|
+
// render KunUI chrome). For the KunUI toolbar/picker/tabs utility classes to be
|
|
69
|
+
// generated, the consuming app @imports this package's shipped `tailwind.css`
|
|
70
|
+
// (which `@source`s the layer's components, path-relative so it's pnpm-safe) in
|
|
71
|
+
// its Tailwind entry — alongside `@import '@kungal/ui-vue/style.css'`. The
|
|
72
|
+
// headless editor itself is still styled by the app's own stylesheet. See README.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungal/editor-nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "KunEditor Nuxt Layer — wraps @kungal/editor-vue and auto-imports <KunEditor> so an existing Nuxt app keeps its exact DX (no import needed).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -27,11 +27,12 @@
|
|
|
27
27
|
"CHANGELOG.md",
|
|
28
28
|
"app",
|
|
29
29
|
"runtime",
|
|
30
|
+
"tailwind.css",
|
|
30
31
|
"nuxt.config.ts"
|
|
31
32
|
],
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@kungal/editor-core": "0.
|
|
34
|
-
"@kungal/editor-vue": "0.
|
|
34
|
+
"@kungal/editor-core": "0.15.0",
|
|
35
|
+
"@kungal/editor-vue": "0.15.0"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"@kungal/ui-vue": "^2.7.0",
|
|
@@ -11,8 +11,15 @@
|
|
|
11
11
|
// KunButton / KunIcon / KunTooltip / KunPopover chrome. It drives the editor
|
|
12
12
|
// purely through the slot API props (KunEditorToolbarApi) — no useInstance.
|
|
13
13
|
//
|
|
14
|
+
// Headings are ONE "text size" KunPopover (Paragraph / H1–H6, each shown at its
|
|
15
|
+
// own size — like the forum's header menu), driven by setHeadingCommand (absolute
|
|
16
|
+
// set). There is deliberately NO math button — an empty inline-math atom is a
|
|
17
|
+
// broken node; math is entered via the `$…$` / `$$` input rules.
|
|
18
|
+
//
|
|
14
19
|
// KunButton/KunIcon/KunTooltip/KunPopover are auto-imported by @kungal/ui-nuxt in
|
|
15
20
|
// the consuming app; icons use the app's iconify set (e.g. lucide via @nuxt/icon).
|
|
21
|
+
// The container/menu utility classes are generated via @kungal/editor-nuxt's
|
|
22
|
+
// shipped tailwind.css (@source) — the consumer @imports it once.
|
|
16
23
|
import { computed, ref } from 'vue'
|
|
17
24
|
import {
|
|
18
25
|
createCodeBlockCommand,
|
|
@@ -23,13 +30,12 @@ import {
|
|
|
23
30
|
toggleStrongCommand,
|
|
24
31
|
wrapInBlockquoteCommand,
|
|
25
32
|
wrapInBulletListCommand,
|
|
26
|
-
wrapInHeadingCommand,
|
|
27
33
|
wrapInOrderedListCommand
|
|
28
34
|
} from '@milkdown/kit/preset/commonmark'
|
|
29
35
|
import { toggleStrikethroughCommand } from '@milkdown/kit/preset/gfm'
|
|
30
36
|
import {
|
|
31
37
|
insertKunSpoilerCommand,
|
|
32
|
-
|
|
38
|
+
setHeadingCommand
|
|
33
39
|
} from '@kungal/editor-core/preset'
|
|
34
40
|
import { EMOJI } from '@kungal/editor-vue'
|
|
35
41
|
import type { KunEditorToolbarApi, StickerPack } from '@kungal/editor-vue'
|
|
@@ -38,20 +44,17 @@ const props = defineProps<KunEditorToolbarApi>()
|
|
|
38
44
|
|
|
39
45
|
const en = computed(() => props.locale.toLowerCase().startsWith('en'))
|
|
40
46
|
const t = computed(() => ({
|
|
47
|
+
textSize: en.value ? 'Text size' : '文本大小',
|
|
41
48
|
bold: en.value ? 'Bold' : '加粗',
|
|
42
49
|
italic: en.value ? 'Italic' : '斜体',
|
|
43
50
|
strike: en.value ? 'Strikethrough' : '删除线',
|
|
44
51
|
code: en.value ? 'Inline code' : '行内代码',
|
|
45
|
-
h1: en.value ? 'Heading 1' : '一级标题',
|
|
46
|
-
h2: en.value ? 'Heading 2' : '二级标题',
|
|
47
|
-
h3: en.value ? 'Heading 3' : '三级标题',
|
|
48
52
|
bulletList: en.value ? 'Bullet list' : '无序列表',
|
|
49
53
|
orderedList: en.value ? 'Ordered list' : '有序列表',
|
|
50
54
|
quote: en.value ? 'Blockquote' : '引用块',
|
|
51
55
|
codeBlock: en.value ? 'Code block' : '代码块',
|
|
52
56
|
hr: en.value ? 'Divider' : '分隔线',
|
|
53
57
|
spoiler: en.value ? 'Spoiler' : '隐藏文本',
|
|
54
|
-
latex: en.value ? 'Math (LaTeX)' : '公式',
|
|
55
58
|
image: en.value ? 'Upload image' : '上传图片',
|
|
56
59
|
picker: en.value ? 'Emoji & stickers' : '表情与贴纸',
|
|
57
60
|
emoji: en.value ? 'Emoji' : '表情',
|
|
@@ -60,14 +63,27 @@ const t = computed(() => ({
|
|
|
60
63
|
failed: en.value ? 'Failed to load stickers' : '贴纸加载失败'
|
|
61
64
|
}))
|
|
62
65
|
|
|
66
|
+
// Paragraph (level 0) + H1–H6, each rendered at its own size in the menu.
|
|
67
|
+
const headingOptions = computed(() => {
|
|
68
|
+
const labels = en.value
|
|
69
|
+
? ['Paragraph', 'Heading 1', 'Heading 2', 'Heading 3', 'Heading 4', 'Heading 5', 'Heading 6']
|
|
70
|
+
: ['正文', '一级标题', '二级标题', '三级标题', '四级标题', '五级标题', '六级标题']
|
|
71
|
+
const sizes = ['1rem', '1.6rem', '1.4rem', '1.25rem', '1.1rem', '1rem', '0.9rem']
|
|
72
|
+
return labels.map((label, level) => ({ level, label, size: sizes[level] }))
|
|
73
|
+
})
|
|
74
|
+
const headingPopover = ref<{ close: () => void } | null>(null)
|
|
75
|
+
const setHeading = (level: number) => {
|
|
76
|
+
props.run(setHeadingCommand.key, level)
|
|
77
|
+
headingPopover.value?.close()
|
|
78
|
+
}
|
|
79
|
+
|
|
63
80
|
interface Tool {
|
|
64
81
|
icon: string
|
|
65
82
|
title: string
|
|
66
83
|
run: () => void
|
|
67
84
|
}
|
|
68
85
|
|
|
69
|
-
//
|
|
70
|
-
// time via api.run (populated once the editor is created).
|
|
86
|
+
// `.key` is read at click time via props.run (populated once the editor exists).
|
|
71
87
|
const groups = computed<Tool[][]>(() => [
|
|
72
88
|
[
|
|
73
89
|
{ icon: 'lucide:bold', title: t.value.bold, run: () => props.run(toggleStrongCommand.key) },
|
|
@@ -75,11 +91,6 @@ const groups = computed<Tool[][]>(() => [
|
|
|
75
91
|
{ icon: 'lucide:strikethrough', title: t.value.strike, run: () => props.run(toggleStrikethroughCommand.key) },
|
|
76
92
|
{ icon: 'lucide:code', title: t.value.code, run: () => props.run(toggleInlineCodeCommand.key) }
|
|
77
93
|
],
|
|
78
|
-
[
|
|
79
|
-
{ icon: 'lucide:heading-1', title: t.value.h1, run: () => props.run(wrapInHeadingCommand.key, 1) },
|
|
80
|
-
{ icon: 'lucide:heading-2', title: t.value.h2, run: () => props.run(wrapInHeadingCommand.key, 2) },
|
|
81
|
-
{ icon: 'lucide:heading-3', title: t.value.h3, run: () => props.run(wrapInHeadingCommand.key, 3) }
|
|
82
|
-
],
|
|
83
94
|
[
|
|
84
95
|
{ icon: 'lucide:list', title: t.value.bulletList, run: () => props.run(wrapInBulletListCommand.key) },
|
|
85
96
|
{ icon: 'lucide:list-ordered', title: t.value.orderedList, run: () => props.run(wrapInOrderedListCommand.key) },
|
|
@@ -88,8 +99,7 @@ const groups = computed<Tool[][]>(() => [
|
|
|
88
99
|
{ icon: 'lucide:minus', title: t.value.hr, run: () => props.run(insertHrCommand.key) }
|
|
89
100
|
],
|
|
90
101
|
[
|
|
91
|
-
{ icon: 'lucide:eye-off', title: t.value.spoiler, run: () => props.run(insertKunSpoilerCommand.key) }
|
|
92
|
-
{ icon: 'lucide:sigma', title: t.value.latex, run: () => props.run(toggleLatexCommand.key) }
|
|
102
|
+
{ icon: 'lucide:eye-off', title: t.value.spoiler, run: () => props.run(insertKunSpoilerCommand.key) }
|
|
93
103
|
]
|
|
94
104
|
])
|
|
95
105
|
|
|
@@ -136,8 +146,27 @@ const insertSticker = (src: string, name: string) =>
|
|
|
136
146
|
|
|
137
147
|
<template>
|
|
138
148
|
<div class="flex flex-wrap items-center gap-0.5">
|
|
149
|
+
<KunPopover ref="headingPopover" position="bottom-start" :opaque="true" inner-class="min-w-40 p-1">
|
|
150
|
+
<template #trigger>
|
|
151
|
+
<KunButton variant="light" size="sm" :aria-label="t.textSize">
|
|
152
|
+
{{ t.textSize }}
|
|
153
|
+
<KunIcon name="lucide:chevron-down" />
|
|
154
|
+
</KunButton>
|
|
155
|
+
</template>
|
|
156
|
+
<button
|
|
157
|
+
v-for="o in headingOptions"
|
|
158
|
+
:key="o.level"
|
|
159
|
+
type="button"
|
|
160
|
+
class="hover:bg-default-100 flex w-full items-center rounded px-3 py-1.5 text-left leading-tight"
|
|
161
|
+
:style="{ fontSize: o.size }"
|
|
162
|
+
@click="setHeading(o.level)"
|
|
163
|
+
>
|
|
164
|
+
{{ o.label }}
|
|
165
|
+
</button>
|
|
166
|
+
</KunPopover>
|
|
167
|
+
|
|
139
168
|
<template v-for="(group, gi) in groups" :key="gi">
|
|
140
|
-
<span
|
|
169
|
+
<span class="bg-default-200 mx-1 h-5 w-px" aria-hidden="true" />
|
|
141
170
|
<KunTooltip v-for="(b, bi) in group" :key="bi" :text="b.title" :delay-show="300">
|
|
142
171
|
<KunButton
|
|
143
172
|
variant="light"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// KunUI view switch for <KunEditor>'s #view-switch slot — the Preview/Markdown
|
|
3
|
+
// tabs as a real <KunTab variant="underlined"> (keyboard nav, sliding indicator,
|
|
4
|
+
// a11y). Same pattern as <KunEditorToolbar>: it lives in this ui-nuxt-assuming
|
|
5
|
+
// layer (not headless editor-vue) and is driven purely by the slot API.
|
|
6
|
+
//
|
|
7
|
+
// <KunEditor v-model="md">
|
|
8
|
+
// <template #view-switch="s"><KunEditorViewSwitch v-bind="s" /></template>
|
|
9
|
+
// </KunEditor>
|
|
10
|
+
//
|
|
11
|
+
// KunTab is auto-imported by @kungal/ui-nuxt in the consuming app.
|
|
12
|
+
import { computed } from 'vue'
|
|
13
|
+
import type { KunEditorViewSwitchApi } from '@kungal/editor-vue'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<KunEditorViewSwitchApi>()
|
|
16
|
+
|
|
17
|
+
const items = computed(() => [
|
|
18
|
+
{ value: 'wysiwyg', textValue: props.labels.wysiwyg },
|
|
19
|
+
{ value: 'source', textValue: props.labels.source }
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
const onChange = (value: string) => {
|
|
23
|
+
props.setMode(value === 'source' ? 'source' : 'wysiwyg')
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<KunTab
|
|
29
|
+
:model-value="mode"
|
|
30
|
+
:items="items"
|
|
31
|
+
variant="underlined"
|
|
32
|
+
color="primary"
|
|
33
|
+
size="sm"
|
|
34
|
+
@update:model-value="onChange"
|
|
35
|
+
/>
|
|
36
|
+
</template>
|
package/tailwind.css
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @kungal/editor-nuxt — Tailwind source registration.
|
|
3
|
+
*
|
|
4
|
+
* <KunEditorToolbar> / <KunEditorViewSwitch> are built with Tailwind utility
|
|
5
|
+
* classes (grids, aspect, sizes, dividers, menu items…). Tailwind v4 does NOT
|
|
6
|
+
* scan node_modules by default, so without this those classes aren't generated
|
|
7
|
+
* and the toolbar / sticker grid render broken (collapsed cells, huge stickers).
|
|
8
|
+
*
|
|
9
|
+
* `@source` resolves relative to THIS file, so it registers the layer's own
|
|
10
|
+
* components regardless of the consumer's node_modules layout (pnpm-safe). Import
|
|
11
|
+
* it ONCE in your Tailwind entry, next to `@import '@kungal/ui-vue/style.css'`:
|
|
12
|
+
*
|
|
13
|
+
* @import 'tailwindcss';
|
|
14
|
+
* @import '@kungal/ui-vue/style.css';
|
|
15
|
+
* @import '@kungal/editor-nuxt/tailwind.css';
|
|
16
|
+
*/
|
|
17
|
+
@source "./runtime";
|