christy-richtext 1.0.0 → 1.1.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/LICENSE CHANGED
@@ -1,21 +1,36 @@
1
- MIT License
1
+ Christy Richtext Proprietary License
2
2
 
3
3
  Copyright (c) 2026 Christy Love (彩虹小馬工作室)
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
5
+ All rights reserved.
6
+
7
+ This software and associated documentation files (the "Software") are proprietary
8
+ and are owned by Christy Love (彩虹小馬工作室).
9
+
10
+ Permission is granted only to individuals or organizations who have obtained a
11
+ valid license from Christy Love (彩虹小馬工作室) to install and use the Software
12
+ according to the terms of their purchased license.
13
+
14
+ Unless expressly permitted by a valid written license agreement, you may not:
15
+
16
+ 1. copy, redistribute, sublicense, sell, rent, lease, or transfer the Software;
17
+ 2. publish, share, or make the Software available to any third party;
18
+ 3. modify, reverse engineer, decompile, or disassemble the Software;
19
+ 4. remove or alter any copyright, trademark, license, or proprietary notice;
20
+ 5. use the Software in any product, service, or project without a valid license.
21
+
22
+ A valid license grants the license holder the right to use the Software only
23
+ within the scope defined by the purchased plan, agreement, invoice, or written
24
+ permission provided by Christy Love (彩虹小馬工作室).
25
+
26
+ The Software is provided "AS IS", without warranty of any kind, express or
27
+ implied, including but not limited to the warranties of merchantability, fitness
28
+ for a particular purpose, and non-infringement.
29
+
30
+ In no event shall the authors or copyright holders be liable for any claim,
31
+ damages, or other liability, whether in an action of contract, tort, or
32
+ otherwise, arising from, out of, or in connection with the Software or the use
33
+ or other dealings in the Software.
34
+
35
+ Unauthorized use, copying, distribution, or modification of this Software is
36
+ strictly prohibited and may result in legal action.
package/README.md CHANGED
@@ -1,42 +1,153 @@
1
1
  # christy-richtext
2
2
 
3
- This template should help get you started developing with Vue 3 in Vite.
3
+ `christy-richtext` 是一個基於 Vue 3 的富文字編輯器元件,適合用在後台管理系統、文章編輯、公告內容、商品描述等需要輸入格式化文字的場景。
4
4
 
5
- ## Recommended IDE Setup
5
+ ## Features
6
6
 
7
- [VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
7
+ * 支援 Vue 3
8
+ * 支援 TypeScript
9
+ * 支援 `v-model`
10
+ * 可作為表單輸入元件使用
11
+ * 適合 Vite / Vue 專案使用
8
12
 
9
- ## Recommended Browser Setup
13
+ ## Installation
10
14
 
11
- - Chromium-based browsers (Chrome, Edge, Brave, etc.):
12
- - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
13
- - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
14
- - Firefox:
15
- - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
16
- - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
15
+ 使用 npm 安裝:
17
16
 
18
- ## Type Support for `.vue` Imports in TS
17
+ ```sh
18
+ npm install christy-richtext
19
+ ```
20
+
21
+ ## Basic Usage
22
+
23
+ ```vue
24
+ <script setup lang="ts">
25
+ import { ref } from 'vue'
26
+ import ChristyRichtext from 'christy-richtext'
27
+
28
+ // 控制富文字編輯器的 HTML 內容
29
+ const content = ref('<p>Hello christy-richtext</p>')
30
+ </script>
31
+
32
+ <template>
33
+ <!-- 富文字編輯器,使用 v-model 綁定內容 -->
34
+ <ChristyRichtext v-model="content" />
35
+
36
+ <!-- 預覽目前輸出的 HTML 內容 -->
37
+ <div v-html="content"></div>
38
+ </template>
39
+ ```
40
+
41
+ ## Props
42
+
43
+ | Prop | Type | Default | Description |
44
+ | ------------ | -------- | ------- | -------------- |
45
+ | `modelValue` | `string` | `''` | 編輯器目前的 HTML 內容 |
46
+
47
+ ## Emits
48
+
49
+ | Event | Payload | Description |
50
+ | ------------------- | -------- | ----------- |
51
+ | `update:modelValue` | `string` | 當編輯器內容變更時觸發 |
52
+
53
+ ## Example
54
+
55
+ ```vue
56
+ <script setup lang="ts">
57
+ import { ref } from 'vue'
58
+ import ChristyRichtext from 'christy-richtext'
59
+
60
+ // 控制公告內容
61
+ const announcementContent = ref('')
62
+
63
+ // 模擬送出公告內容
64
+ const submit = () => {
65
+ console.log('公告內容:', announcementContent.value)
66
+ }
67
+ </script>
68
+
69
+ <template>
70
+ <section>
71
+ <h2>新增公告</h2>
72
+
73
+ <!-- 公告內容輸入區 -->
74
+ <ChristyRichtext v-model="announcementContent" />
19
75
 
20
- TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
76
+ <!-- 送出按鈕 -->
77
+ <button type="button" @click="submit">
78
+ 送出
79
+ </button>
80
+ </section>
81
+ </template>
82
+ ```
83
+
84
+ ## Usage in Nuxt
85
+
86
+ 如果你要在 Nuxt 專案中使用,建議使用 `<ClientOnly>` 包起來,避免富文字編輯器在伺服器端渲染時遇到瀏覽器 API 錯誤。
21
87
 
22
- ## Customize configuration
88
+ ```vue
89
+ <script setup lang="ts">
90
+ import { ref } from 'vue'
91
+ import ChristyRichtext from 'christy-richtext'
23
92
 
24
- See [Vite Configuration Reference](https://vite.dev/config/).
93
+ // 控制富文字內容
94
+ const content = ref('')
95
+ </script>
96
+
97
+ <template>
98
+ <ClientOnly>
99
+ <ChristyRichtext v-model="content" />
100
+ </ClientOnly>
101
+ </template>
102
+ ```
25
103
 
26
- ## Project Setup
104
+ ## Development
105
+
106
+ 安裝專案依賴:
27
107
 
28
108
  ```sh
29
109
  npm install
30
110
  ```
31
111
 
32
- ### Compile and Hot-Reload for Development
112
+ 啟動開發環境:
33
113
 
34
114
  ```sh
35
115
  npm run dev
36
116
  ```
37
117
 
38
- ### Type-Check, Compile and Minify for Production
118
+ 建置專案:
39
119
 
40
120
  ```sh
41
121
  npm run build
42
122
  ```
123
+
124
+ 執行型別檢查:
125
+
126
+ ```sh
127
+ npm run type-check
128
+ ```
129
+
130
+ ## Project Structure
131
+
132
+ ```txt
133
+ christy-richtext/
134
+ ├─ src/
135
+ │ ├─ components/
136
+ │ │ └─ ChristyRichtext.vue
137
+ │ ├─ index.ts
138
+ │ └─ style.css
139
+ ├─ package.json
140
+ ├─ README.md
141
+ ├─ tsconfig.json
142
+ └─ vite.config.ts
143
+ ```
144
+
145
+ ## Notes
146
+
147
+ 如果你在頁面上使用 `v-html` 顯示富文字內容,請注意 HTML 內容來源是否可信。
148
+
149
+ 若內容來自使用者輸入,建議在後端或前端進行 HTML 清理,避免 XSS 攻擊。
150
+
151
+ ## License
152
+
153
+ MIT
@@ -1,4 +1,59 @@
1
1
 
2
+ .crt-img-nv[data-v-2f71d5d7] {
3
+ /* 定位由 outerStyle 動態注入 */
4
+ }
5
+ .crt-img-container[data-v-2f71d5d7] {
6
+ user-select: none;
7
+ }
8
+ .crt-img-el[data-v-2f71d5d7] {
9
+ display: block;
10
+ width: 100%;
11
+ height: auto;
12
+ max-width: 100%;
13
+ transition: opacity 0.15s;
14
+ }
15
+ .crt-img-el--selected[data-v-2f71d5d7] {
16
+ outline: 2px solid #2563eb;
17
+ outline-offset: 1px;
18
+ }
19
+
20
+ /* 移動 icon(自由浮動模式) */
21
+ .crt-move-handle[data-v-2f71d5d7] {
22
+ position: absolute;
23
+ top: 4px;
24
+ left: 50%;
25
+ transform: translateX(-50%);
26
+ background: #2563ebcc;
27
+ color: #fff;
28
+ font-size: 14px;
29
+ border-radius: 4px;
30
+ padding: 0 6px 1px;
31
+ cursor: move;
32
+ user-select: none;
33
+ z-index: 20;
34
+ line-height: 1.6;
35
+ }
36
+
37
+ /* Resize handles */
38
+ .crt-rh[data-v-2f71d5d7] {
39
+ position: absolute;
40
+ width: 10px;
41
+ height: 10px;
42
+ background: #2563eb;
43
+ border: 2px solid #fff;
44
+ border-radius: 2px;
45
+ z-index: 10;
46
+ box-shadow: 0 1px 3px rgba(0,0,0,.25);
47
+ }
48
+ .crt-rh--nw[data-v-2f71d5d7] { top: -5px; left: -5px; cursor: nw-resize;
49
+ }
50
+ .crt-rh--ne[data-v-2f71d5d7] { top: -5px; right: -5px; cursor: ne-resize;
51
+ }
52
+ .crt-rh--sw[data-v-2f71d5d7] { bottom: -5px; left: -5px; cursor: sw-resize;
53
+ }
54
+ .crt-rh--se[data-v-2f71d5d7] { bottom: -5px; right: -5px; cursor: se-resize;
55
+ }
56
+
2
57
  /* === Wrapper === */
3
58
  .crt-editor-wrapper {
4
59
  display: flex;
@@ -44,6 +99,37 @@
44
99
  .crt-input-width:focus {
45
100
  border-color: #2563eb;
46
101
  }
102
+
103
+ /* 透明度滑桿 */
104
+ .crt-input-opacity {
105
+ width: 80px;
106
+ height: 4px;
107
+ cursor: pointer;
108
+ accent-color: #2563eb;
109
+ }
110
+ .crt-opacity-val {
111
+ font-size: 11px;
112
+ color: #6b7280;
113
+ min-width: 28px;
114
+ text-align: right;
115
+ }
116
+
117
+ /* 自由浮動按鈕 */
118
+ .crt-btn--free {
119
+ background: #fdf4ff;
120
+ color: #7e22ce;
121
+ border: 1px solid #e9d5ff;
122
+ font-size: 12px;
123
+ padding: 0 8px;
124
+ }
125
+ .crt-btn--free:hover:not(:disabled) {
126
+ background: #f3e8ff;
127
+ }
128
+ .crt-btn--free.crt-btn--active {
129
+ background: #7e22ce;
130
+ color: #fff;
131
+ border-color: #7e22ce;
132
+ }
47
133
  .crt-btn--word {
48
134
  background: #f0fdf4;
49
135
  color: #15803d;
@@ -239,6 +325,7 @@
239
325
  min-height: 200px;
240
326
  outline: none;
241
327
  overflow-y: auto;
328
+ position: relative;
242
329
  }
243
330
  .crt-editor-content .tiptap {
244
331
  outline: none;
@@ -246,6 +333,7 @@
246
333
  font-size: 15px;
247
334
  line-height: 1.7;
248
335
  color: #111827;
336
+ position: relative;
249
337
  }
250
338
 
251
339
  /* 文繞圖 clearfix */
@@ -255,7 +343,7 @@
255
343
  clear: both;
256
344
  }
257
345
 
258
- /* 選取圖片 highlight */
346
+ /* 選取圖片 highlight(NodeView 接管後已由 selected prop 控制,保留備用) */
259
347
  .crt-editor-content .tiptap img.ProseMirror-selectednode {
260
348
  outline: 2px solid #2563eb;
261
349
  outline-offset: 2px;
@@ -383,6 +471,7 @@
383
471
  min-height: 200px;
384
472
  outline: none;
385
473
  overflow-y: auto;
474
+ position: relative;
386
475
  }
387
476
  .crt-editor-content .tiptap {
388
477
  outline: none;
@@ -390,6 +479,7 @@
390
479
  font-size: 15px;
391
480
  line-height: 1.7;
392
481
  color: #111827;
482
+ position: relative;
393
483
  }
394
484
 
395
485
  /* 文繞圖 clearfix */
@@ -399,7 +489,7 @@
399
489
  clear: both;
400
490
  }
401
491
 
402
- /* 選取圖片 highlight */
492
+ /* 選取圖片 highlight(NodeView 接管後已由 selected prop 控制,保留備用) */
403
493
  .crt-editor-content .tiptap img.ProseMirror-selectednode {
404
494
  outline: 2px solid #2563eb;
405
495
  outline-offset: 2px;
@@ -491,6 +581,7 @@
491
581
  min-height: 200px;
492
582
  outline: none;
493
583
  overflow-y: auto;
584
+ position: relative;
494
585
  }
495
586
  .crt-editor-content .tiptap {
496
587
  outline: none;
@@ -498,6 +589,7 @@
498
589
  font-size: 15px;
499
590
  line-height: 1.7;
500
591
  color: #111827;
592
+ position: relative;
501
593
  }
502
594
 
503
595
  /* 文繞圖 clearfix */
@@ -507,7 +599,7 @@
507
599
  clear: both;
508
600
  }
509
601
 
510
- /* 選取圖片 highlight */
602
+ /* 選取圖片 highlight(NodeView 接管後已由 selected prop 控制,保留備用) */
511
603
  .crt-editor-content .tiptap img.ProseMirror-selectednode {
512
604
  outline: 2px solid #2563eb;
513
605
  outline-offset: 2px;