@itshixun/qckeditor-plugin-fullscreen 1.0.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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @itshixun/qckeditor-plugin-fullscreen
2
+
3
+ CKEditor 5 插件:全屏编辑模式。点击工具栏按钮切换编辑器全屏/退出全屏。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @itshixun/qckeditor-plugin-fullscreen
9
+ # 或
10
+ pnpm add @itshixun/qckeditor-plugin-fullscreen
11
+ ```
12
+
13
+ 依赖 `ckeditor5`(peerDependencies,需自行安装)。
14
+
15
+ ## 基本使用
16
+
17
+ ### 1. 引入样式
18
+
19
+ ```ts
20
+ import '@itshixun/qckeditor-plugin-fullscreen/dist/index.css';
21
+ ```
22
+
23
+ ### 2. 注册插件
24
+
25
+ ```ts
26
+ import { ClassicEditor } from 'ckeditor5';
27
+ import { FullScreen } from '@itshixun/qckeditor-plugin-fullscreen';
28
+
29
+ const editor = await ClassicEditor.create(element, {
30
+ plugins: [
31
+ // ... 其他插件
32
+ FullScreen,
33
+ ],
34
+ toolbar: [
35
+ // ... 其他按钮
36
+ 'fullScreen', // 工具栏按钮名称:全屏
37
+ ],
38
+ fullScreen: {
39
+ // 可选:自定义 z-index,默认 1000
40
+ zIndex: 2000,
41
+ },
42
+ });
43
+ ```
44
+
45
+ ### 3. Vue 中使用
46
+
47
+ ```vue
48
+ <script setup lang="ts">
49
+ import { ClassicEditor } from 'ckeditor5';
50
+ import { FullScreen } from '@itshixun/qckeditor-plugin-fullscreen';
51
+
52
+ const config = {
53
+ editor: ClassicEditor,
54
+ plugins: [/* ... */, FullScreen],
55
+ toolbar: ['bold', 'italic', 'fullScreen'],
56
+ fullScreen: {
57
+ zIndex: 2000,
58
+ },
59
+ };
60
+ </script>
61
+
62
+ <template>
63
+ <ckeditor :editor="config.editor" :config="config" />
64
+ </template>
65
+ ```
66
+
67
+ ## 配置项
68
+
69
+ | 属性 | 类型 | 必填 | 说明 |
70
+ |------|------|------|------|
71
+ | `zIndex` | `number` | 否 | 全屏模式下的 z-index,默认 `1000` |
72
+
73
+ ## 命令说明
74
+
75
+ ### `fullScreen` — 切换全屏模式
76
+
77
+ ```ts
78
+ // 手动切换全屏状态
79
+ editor.execute('fullScreen');
80
+
81
+ // 获取当前全屏状态
82
+ const isFullScreen = editor.commands.get('fullScreen')!.value;
83
+ ```
84
+
85
+ ## 插件行为
86
+
87
+ 1. 点击工具栏按钮进入全屏模式
88
+ 2. 全屏时编辑器占据整个视口,工具栏置顶
89
+ 3. 再次点击按钮退出全屏,恢复原始布局
90
+ 4. 全屏时自动隐藏页面滚动条
91
+
92
+ ## 类型支持
93
+
94
+ 导入插件后,`EditorConfig` 类型自动扩展:
95
+
96
+ ```ts
97
+ const config: EditorConfig = {
98
+ // 无类型错误,fullScreen 已声明
99
+ fullScreen: {
100
+ zIndex: 2000,
101
+ },
102
+ };
103
+ ```
104
+
105
+ ## 导出 API
106
+
107
+ ```ts
108
+ import {
109
+ FullScreen, // 主插件(Editing + UI)
110
+ FullScreenEditing, // 编辑插件(注册 fullScreen 命令)
111
+ FullScreenUI, // UI 插件(工具栏按钮)
112
+ FullScreenCommand, // 全屏命令
113
+ type FullScreenConfig,
114
+ } from '@itshixun/qckeditor-plugin-fullscreen';
115
+ ```
@@ -0,0 +1,12 @@
1
+ import { Plugin } from 'ckeditor5';
2
+ import { FullScreenEditing } from './fullscreenediting.js';
3
+ import { FullScreenUI } from './fullscreenui.js';
4
+ /**
5
+ * FullScreen 主插件
6
+ * 聚合 Editing 和 UI 功能
7
+ */
8
+ export declare class FullScreen extends Plugin {
9
+ static get pluginName(): "FullScreen";
10
+ static get requires(): readonly [typeof FullScreenEditing, typeof FullScreenUI];
11
+ }
12
+ //# sourceMappingURL=fullscreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fullscreen.d.ts","sourceRoot":"","sources":["../src/fullscreen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,MAAM;IACpC,WAAkB,UAAU,IACnB,YAAY,CACpB;IAED,WAAkB,QAAQ,6DAEzB;CACF"}
@@ -0,0 +1,45 @@
1
+ import { Command } from 'ckeditor5';
2
+ /**
3
+ * 全屏切换命令
4
+ *
5
+ * 修复说明:
6
+ * 当编辑器进入全屏模式(position: fixed)后,CKEditor 5 的 Rect.getVisible()
7
+ * 在计算 tooltip 等 balloon panel 的位置时,会继续检查编辑器原父链上的 overflow 裁剪。
8
+ * 如果父链中有 overflow: hidden 的容器(如 Vue2 演示项目中的 .editor-wrapper),
9
+ * 且该容器不在视口内,getVisible() 会返回 null,导致 tooltip 被定位到视口外(-99999px)。
10
+ *
11
+ * 根因:Rect.getVisible() 对 position: fixed 的处理与 CSS 规范不一致——
12
+ * fixed 定位元素实际不会被普通 overflow 容器裁剪,但 Rect.getVisible() 没有正确跳过。
13
+ *
14
+ * 修复方案:仿照 CKEditor 5 官方 fullscreen 插件的做法,进入全屏时将编辑器元素
15
+ * 移动到 body 下,彻底脱离原 DOM 上下文,避免被祖先 overflow 裁剪影响。
16
+ * 退出全屏时恢复原位置。
17
+ *
18
+ * 参考:https://github.com/ckeditor/ckeditor5/issues/14798(类似问题)
19
+ */
20
+ export declare class FullScreenCommand extends Command {
21
+ /**
22
+ * 当前全屏状态
23
+ */
24
+ value: boolean;
25
+ /**
26
+ * 进入全屏时创建的占位元素,用于退出时恢复原位置
27
+ */
28
+ private _placeholder;
29
+ /**
30
+ * 进入全屏时保存的原父元素,用于退出时恢复
31
+ */
32
+ private _originalParent;
33
+ refresh(): void;
34
+ execute(): void;
35
+ /**
36
+ * 将编辑器元素恢复到原来的 DOM 位置
37
+ */
38
+ private _restoreEditorPosition;
39
+ /**
40
+ * 清理全屏状态
41
+ * 在编辑器销毁时调用,防止 body overflow 等全局样式泄漏
42
+ */
43
+ cleanup(): void;
44
+ }
45
+ //# sourceMappingURL=fullscreencommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fullscreencommand.d.ts","sourceRoot":"","sources":["../src/fullscreencommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAkB,SAAQ,OAAO;IAC5C;;OAEG;IACa,KAAK,UAAS;IAE9B;;OAEG;IACH,OAAO,CAAC,YAAY,CAA4B;IAEhD;;OAEG;IACH,OAAO,CAAC,eAAe,CAAqB;IAE5B,OAAO,IAAI,IAAI;IAIf,OAAO,IAAI,IAAI;IAsD/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAQ9B;;;OAGG;IACI,OAAO,IAAI,IAAI;CAsBvB"}
@@ -0,0 +1,10 @@
1
+ import { Plugin } from 'ckeditor5';
2
+ /**
3
+ * FullScreen 编辑插件
4
+ * 负责注册 fullscreen 命令
5
+ */
6
+ export declare class FullScreenEditing extends Plugin {
7
+ static get pluginName(): "FullScreenEditing";
8
+ init(): void;
9
+ }
10
+ //# sourceMappingURL=fullscreenediting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fullscreenediting.d.ts","sourceRoot":"","sources":["../src/fullscreenediting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,WAAkB,UAAU,IACnB,mBAAmB,CAC3B;IAEM,IAAI,IAAI,IAAI;CAUpB"}
@@ -0,0 +1,10 @@
1
+ import { Plugin } from 'ckeditor5';
2
+ /**
3
+ * FullScreen UI 插件
4
+ * 负责工具栏按钮(全屏/取消全屏切换)
5
+ */
6
+ export declare class FullScreenUI extends Plugin {
7
+ static get pluginName(): "FullScreenUI";
8
+ init(): void;
9
+ }
10
+ //# sourceMappingURL=fullscreenui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fullscreenui.d.ts","sourceRoot":"","sources":["../src/fullscreenui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,WAAW,CAAC;AAO/C;;;GAGG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACtC,WAAkB,UAAU,IACnB,cAAc,CACtB;IAEM,IAAI,IAAI,IAAI;CAiCpB"}
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .ck-fullscreen{position:fixed!important;top:0!important;left:0!important;right:0!important;bottom:0!important;z-index:var(--ck-fullscreen-z-index, 1000)!important}.ck-fullscreen .ck-sticky-panel__content{top:0!important;width:100%!important}.ck-fullscreen .ck-editor__editable.ck-rounded-corners.ck-editor__editable_inline,.ck-fullscreen .ck.ck-editor__main{height:100%}body:has(.ck-fullscreen) .ck-body-wrapper{z-index:calc(var(--ck-fullscreen-z-index, 1000) + 1)!important}
@@ -0,0 +1,13 @@
1
+ import { FullScreenConfig } from './types.js';
2
+ declare module 'ckeditor5' {
3
+ interface EditorConfig {
4
+ /** FullScreen 插件配置 */
5
+ fullScreen?: FullScreenConfig;
6
+ }
7
+ }
8
+ export { FullScreen } from './fullscreen.js';
9
+ export { FullScreenEditing } from './fullscreenediting.js';
10
+ export { FullScreenUI } from './fullscreenui.js';
11
+ export { FullScreenCommand } from './fullscreencommand.js';
12
+ export type { FullScreenConfig } from './types.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,QAAQ,WAAW,CAAC;IACzB,UAAU,YAAY;QACpB,sBAAsB;QACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;KAC/B;CACF;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,98 @@
1
+ var u = Object.defineProperty;
2
+ var h = (n, t, e) => t in n ? u(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
+ var c = (n, t, e) => h(n, typeof t != "symbol" ? t + "" : t, e);
4
+ import { Command as p, Plugin as d, ButtonView as m } from "ckeditor5";
5
+ class v extends p {
6
+ constructor() {
7
+ super(...arguments);
8
+ /**
9
+ * 当前全屏状态
10
+ */
11
+ c(this, "value", !1);
12
+ /**
13
+ * 进入全屏时创建的占位元素,用于退出时恢复原位置
14
+ */
15
+ c(this, "_placeholder", null);
16
+ /**
17
+ * 进入全屏时保存的原父元素,用于退出时恢复
18
+ */
19
+ c(this, "_originalParent", null);
20
+ }
21
+ refresh() {
22
+ this.isEnabled = !0;
23
+ }
24
+ execute() {
25
+ const e = !this.value, r = this.editor, o = r.config.get("fullScreen"), i = (o == null ? void 0 : o.zIndex) ?? 1e3, l = r.ui.element;
26
+ if (!l)
27
+ return;
28
+ const s = document.querySelector(".ck-body-wrapper");
29
+ e ? (this._originalParent = l.parentNode, this._placeholder = document.createElement("div"), this._placeholder.style.display = "none", this._originalParent.replaceChild(this._placeholder, l), document.body.appendChild(l), l.classList.add("ck-fullscreen"), l.style.setProperty("--ck-fullscreen-z-index", String(i)), document.body.style.overflow = "hidden", s && s.style.setProperty("z-index", String(i + 1), "important"), window.dispatchEvent(new Event("resize"))) : (this._restoreEditorPosition(l), l.classList.remove("ck-fullscreen"), l.style.removeProperty("--ck-fullscreen-z-index"), document.body.style.overflow = "", s && s.style.removeProperty("z-index")), this.value = e;
30
+ }
31
+ /**
32
+ * 将编辑器元素恢复到原来的 DOM 位置
33
+ */
34
+ _restoreEditorPosition(e) {
35
+ this._placeholder && this._originalParent && (this._originalParent.replaceChild(e, this._placeholder), this._placeholder = null, this._originalParent = null);
36
+ }
37
+ /**
38
+ * 清理全屏状态
39
+ * 在编辑器销毁时调用,防止 body overflow 等全局样式泄漏
40
+ */
41
+ cleanup() {
42
+ if (!this.value)
43
+ return;
44
+ const e = this.editor.ui.element;
45
+ e && (this._restoreEditorPosition(e), e.classList.remove("ck-fullscreen"), e.style.removeProperty("--ck-fullscreen-z-index"));
46
+ const r = document.querySelector(".ck-body-wrapper");
47
+ r && r.style.removeProperty("z-index"), document.body.style.overflow = "", this.value = !1;
48
+ }
49
+ }
50
+ class g extends d {
51
+ static get pluginName() {
52
+ return "FullScreenEditing";
53
+ }
54
+ init() {
55
+ const t = new v(this.editor);
56
+ this.editor.commands.add("fullScreen", t), this.listenTo(this.editor, "destroy", () => {
57
+ t.cleanup();
58
+ });
59
+ }
60
+ }
61
+ const a = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32"><path fill="currentColor" d="M20,8l8,8V8H20z M4,24h8l-8-8V24z"/><path fill="currentColor" d="M32,28V4H0v24h14v2H8v2h16v-2h-6v-2H32z M2,26V6h28v20H2z"/></svg>', f = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32"><path fill="currentColor" d="M4,16v8h8L4,16z M0,4v24h14v2H8v2h16v-0.06c2.702-0.299,5.042-1.791,6.481-3.94H32V4H0z M23,29.999 c-3.865-0.008-6.994-3.135-7-6.999c0.006-3.865,3.135-6.994,7-7c3.864,0.006,6.991,3.135,6.999,7 C29.991,26.864,26.864,29.991,23,29.999z M30,17.35c-0.57-0.707-1.244-1.326-2-1.832V8h-8l6.896,6.896 C25.717,14.328,24.398,14,23,14c-4.972,0-9,4.028-9,9c0,1.054,0.19,2.061,0.523,3H2V6h28V17.35z"/><polygon fill="currentColor" points="19,25 21,27 23,25 25,27 27,25 25,23 27,21 25,19 23,21 21,19 19,21 21,23"/></svg>';
62
+ class y extends d {
63
+ static get pluginName() {
64
+ return "FullScreenUI";
65
+ }
66
+ init() {
67
+ const t = this.editor, e = t.commands.get("fullScreen"), r = t.locale.t;
68
+ t.ui.componentFactory.add("fullScreen", (o) => {
69
+ const i = new m(o);
70
+ return i.set({
71
+ label: r("全屏"),
72
+ icon: a,
73
+ tooltip: !0
74
+ }), i.bind("isEnabled").to(e, "isEnabled"), this.listenTo(i, "execute", () => {
75
+ t.execute("fullScreen");
76
+ const l = e.value;
77
+ i.set("isOn", l), i.set({
78
+ label: r(l ? "取消全屏" : "全屏"),
79
+ icon: l ? f : a
80
+ });
81
+ }), i;
82
+ });
83
+ }
84
+ }
85
+ class S extends d {
86
+ static get pluginName() {
87
+ return "FullScreen";
88
+ }
89
+ static get requires() {
90
+ return [g, y];
91
+ }
92
+ }
93
+ export {
94
+ S as FullScreen,
95
+ v as FullScreenCommand,
96
+ g as FullScreenEditing,
97
+ y as FullScreenUI
98
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * FullScreen 插件配置
3
+ */
4
+ export interface FullScreenConfig {
5
+ /** 全屏模式 z-index,默认 1000 */
6
+ zIndex?: number;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@itshixun/qckeditor-plugin-fullscreen",
3
+ "version": "1.0.0",
4
+ "description": "CKEditor 5 plugin for fullscreen editing",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "build:lib": "tsc && vite build",
17
+ "dev:lib": "vite build --watch",
18
+ "release": "pnpm build:lib && npm publish --access public"
19
+ },
20
+ "peerDependencies": {
21
+ "ckeditor5": ">=42.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "ckeditor5": "^47.6.1",
25
+ "typescript": "^5.7.3",
26
+ "vite": "^6.0.0",
27
+ "vite-plugin-dts": "^4.5.4"
28
+ },
29
+ "keywords": [
30
+ "ckeditor",
31
+ "ckeditor5",
32
+ "plugin",
33
+ "fullscreen"
34
+ ],
35
+ "license": "MIT"
36
+ }