@thangph2146/nextjs-editor 1.0.4 → 1.0.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.
- package/README.md +49 -1
- package/dist/editor-utilities-raw.css +17 -16
- package/dist/editor-utilities-scoped.css +17 -16
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1343 -1338
- package/package.json +90 -89
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Trong `app/layout.tsx` hoặc `_app.tsx`:
|
|
|
26
26
|
import "@thangph2146/nextjs-editor/styles.css"
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
**Lưu ý:** Chỉ cần import file trên. Bạn **không** cần thêm `@source` hay cấu hình nào trong `globals.css`. Style editor được đóng gói sẵn
|
|
29
|
+
**Lưu ý:** Chỉ cần import file trên. Bạn **không** cần thêm `@source` hay cấu hình nào trong `globals.css`. Style editor được đóng gói sẵn, scope trong `#editor-x`, nằm trong layer `nextjs-editor`, và **mọi declaration đều có `!important`** — dự án app (tuyen-sinh, tuyen-sinh-admin, v.v.) **không ghi đè được** style editor.
|
|
30
30
|
|
|
31
31
|
### 2. Dùng component Editor (Client Component)
|
|
32
32
|
|
|
@@ -64,6 +64,54 @@ export function MyEditor() {
|
|
|
64
64
|
- **Ảnh**: Mặc định dialog chèn ảnh có tab **URL** và **File**. Để tab **Thư viện** hiển thị ảnh từ API của project, xem [Cấu hình API thư viện ảnh](#cấu-hình-api-thư-viện-ảnh) bên dưới.
|
|
65
65
|
- **Next.js**: Package dùng `next/image` và `next/dynamic` khi chạy trong Next.js; cần cài `next` trong project.
|
|
66
66
|
|
|
67
|
+
## Tránh SCSS/CSS của app ghi đè editor
|
|
68
|
+
|
|
69
|
+
Style editor được build với **`!important`** trên mọi declaration (dùng [postcss-safe-important](https://github.com/Crimx/postcss-safe-important); keyframes và animation được loại trừ theo mặc định). Do đó **các dự án app (tuyen-sinh, tuyen-sinh-admin, v.v.) không ghi đè được** style bên trong `#editor-x`, kể cả khi SCSS/global của app là unlayered hoặc có specificity cao hơn.
|
|
70
|
+
|
|
71
|
+
Style vẫn được bọc trong **`@layer nextjs-editor`**. Nếu bạn muốn thêm một lớp bảo vệ theo thứ tự layer (ví dụ đảm bảo SCSS app không bao giờ thắng khi specificity ngang nhau), có thể đưa SCSS/global của app vào layer `app` và khai báo thứ tự layer sao cho `nextjs-editor` đứng **sau**.
|
|
72
|
+
|
|
73
|
+
### Bước 1 (tùy chọn): Khai báo thứ tự layer trong app
|
|
74
|
+
|
|
75
|
+
Trong `globals.css` (hoặc file CSS chính), **dòng đầu tiên** khai báo thứ tự layer, thêm `app` và `nextjs-editor` (layer xuất hiện sau có ưu tiên cao hơn):
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
@layer legacy, base, components, utilities, app, nextjs-editor;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Bước 2 (tùy chọn): Đưa SCSS/global vào layer `app`
|
|
82
|
+
|
|
83
|
+
Mọi style global/SCSS không nằm trong Tailwind cần nằm trong `@layer app`. **Lưu ý:** Trong Sass, `@use` không được phép bên trong `@layer`, nên không bọc trực tiếp nội dung có `@use` trong một block `@layer app { }`.
|
|
84
|
+
|
|
85
|
+
**Cách khuyến nghị — File wrapper dùng `@import`:**
|
|
86
|
+
|
|
87
|
+
Tạo file SCSS mới (ví dụ `src/styles/app-layer.scss`) chỉ dùng `@import` (Sass cho phép `@import` trong `@layer`):
|
|
88
|
+
|
|
89
|
+
```scss
|
|
90
|
+
@layer app {
|
|
91
|
+
@import "main";
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Trong `layout.tsx` (hoặc nơi đang import file SCSS chính), đổi sang import file wrapper:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import "../styles/app-layer.scss";
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Cách khác — File CSS import SCSS (nếu bundler hỗ trợ):**
|
|
102
|
+
|
|
103
|
+
Tạo file `src/app/globals-app.css`:
|
|
104
|
+
|
|
105
|
+
```css
|
|
106
|
+
@layer app {
|
|
107
|
+
@import "../styles/main.scss";
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Rồi trong `layout.tsx` import sau `globals.css`: `import "./globals-app.css"`. (Một số bundler có thể không compile `.scss` khi import từ `.css`.)
|
|
112
|
+
|
|
113
|
+
Sau khi cấu hình (nếu dùng), style trong layer `nextjs-editor` (đã load khi import `@thangph2146/nextjs-editor/styles.css`) và có `!important` sẽ luôn thắng so với SCSS của app; cấu trúc Tailwind và theme của editor trong `#editor-x` không bị ghi đè.
|
|
114
|
+
|
|
67
115
|
## Cấu hình API thư viện ảnh
|
|
68
116
|
|
|
69
117
|
Tab **Thư viện** trong dialog chèn ảnh cần dữ liệu từ API/uploads của project. Bạn cấu hình bằng cách **alias** module uploads-hooks của package sang file hooks trong project.
|
|
@@ -591,6 +591,9 @@
|
|
|
591
591
|
.h-\[var\(--radix-select-trigger-height\)\] {
|
|
592
592
|
height: var(--radix-select-trigger-height);
|
|
593
593
|
}
|
|
594
|
+
.h-auto {
|
|
595
|
+
height: auto;
|
|
596
|
+
}
|
|
594
597
|
.h-full {
|
|
595
598
|
height: 100%;
|
|
596
599
|
}
|
|
@@ -648,9 +651,6 @@
|
|
|
648
651
|
.min-h-\[54px\] {
|
|
649
652
|
min-height: 54px;
|
|
650
653
|
}
|
|
651
|
-
.min-h-\[70vh\] {
|
|
652
|
-
min-height: 70vh;
|
|
653
|
-
}
|
|
654
654
|
.min-h-\[300px\] {
|
|
655
655
|
min-height: 300px;
|
|
656
656
|
}
|
|
@@ -1135,6 +1135,10 @@
|
|
|
1135
1135
|
border-start-end-radius: 0;
|
|
1136
1136
|
border-end-end-radius: 0;
|
|
1137
1137
|
}
|
|
1138
|
+
.rounded-t-xl {
|
|
1139
|
+
border-top-left-radius: var(--radius-xl);
|
|
1140
|
+
border-top-right-radius: var(--radius-xl);
|
|
1141
|
+
}
|
|
1138
1142
|
.rounded-b-xl {
|
|
1139
1143
|
border-bottom-right-radius: var(--radius-xl);
|
|
1140
1144
|
border-bottom-left-radius: var(--radius-xl);
|
|
@@ -1262,10 +1266,10 @@
|
|
|
1262
1266
|
background-color: color-mix(in oklab, var(--background) 95%, transparent);
|
|
1263
1267
|
}
|
|
1264
1268
|
}
|
|
1265
|
-
.bg-black\/
|
|
1266
|
-
background-color: color-mix(in srgb, #000
|
|
1269
|
+
.bg-black\/10 {
|
|
1270
|
+
background-color: color-mix(in srgb, #000 10%, transparent);
|
|
1267
1271
|
@supports (color: color-mix(in lab, red, red)) {
|
|
1268
|
-
background-color: color-mix(in oklab, var(--color-black)
|
|
1272
|
+
background-color: color-mix(in oklab, var(--color-black) 10%, transparent);
|
|
1269
1273
|
}
|
|
1270
1274
|
}
|
|
1271
1275
|
.bg-black\/60 {
|
|
@@ -1328,12 +1332,6 @@
|
|
|
1328
1332
|
background-color: color-mix(in oklab, var(--muted) 20%, transparent);
|
|
1329
1333
|
}
|
|
1330
1334
|
}
|
|
1331
|
-
.bg-muted\/30 {
|
|
1332
|
-
background-color: var(--muted);
|
|
1333
|
-
@supports (color: color-mix(in lab, red, red)) {
|
|
1334
|
-
background-color: color-mix(in oklab, var(--muted) 30%, transparent);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
1335
|
.bg-muted\/40 {
|
|
1338
1336
|
background-color: var(--muted);
|
|
1339
1337
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1527,12 +1525,12 @@
|
|
|
1527
1525
|
.pt-0 {
|
|
1528
1526
|
padding-top: calc(var(--spacing) * 0);
|
|
1529
1527
|
}
|
|
1528
|
+
.pt-3 {
|
|
1529
|
+
padding-top: calc(var(--spacing) * 3);
|
|
1530
|
+
}
|
|
1530
1531
|
.pt-4 {
|
|
1531
1532
|
padding-top: calc(var(--spacing) * 4);
|
|
1532
1533
|
}
|
|
1533
|
-
.pt-5 {
|
|
1534
|
-
padding-top: calc(var(--spacing) * 5);
|
|
1535
|
-
}
|
|
1536
1534
|
.pt-6 {
|
|
1537
1535
|
padding-top: calc(var(--spacing) * 6);
|
|
1538
1536
|
}
|
|
@@ -1542,6 +1540,9 @@
|
|
|
1542
1540
|
.pr-10 {
|
|
1543
1541
|
padding-right: calc(var(--spacing) * 10);
|
|
1544
1542
|
}
|
|
1543
|
+
.pr-12 {
|
|
1544
|
+
padding-right: calc(var(--spacing) * 12);
|
|
1545
|
+
}
|
|
1545
1546
|
.pb-2 {
|
|
1546
1547
|
padding-bottom: calc(var(--spacing) * 2);
|
|
1547
1548
|
}
|
|
@@ -3879,4 +3880,4 @@
|
|
|
3879
3880
|
--tw-content: "";
|
|
3880
3881
|
}
|
|
3881
3882
|
}
|
|
3882
|
-
}
|
|
3883
|
+
}
|
|
@@ -591,6 +591,9 @@
|
|
|
591
591
|
#editor-x .h-\[var\(--radix-select-trigger-height\)\] {
|
|
592
592
|
height: var(--radix-select-trigger-height);
|
|
593
593
|
}
|
|
594
|
+
#editor-x .h-auto {
|
|
595
|
+
height: auto;
|
|
596
|
+
}
|
|
594
597
|
#editor-x .h-full {
|
|
595
598
|
height: 100%;
|
|
596
599
|
}
|
|
@@ -648,9 +651,6 @@
|
|
|
648
651
|
#editor-x .min-h-\[54px\] {
|
|
649
652
|
min-height: 54px;
|
|
650
653
|
}
|
|
651
|
-
#editor-x .min-h-\[70vh\] {
|
|
652
|
-
min-height: 70vh;
|
|
653
|
-
}
|
|
654
654
|
#editor-x .min-h-\[300px\] {
|
|
655
655
|
min-height: 300px;
|
|
656
656
|
}
|
|
@@ -1135,6 +1135,10 @@
|
|
|
1135
1135
|
border-start-end-radius: 0;
|
|
1136
1136
|
border-end-end-radius: 0;
|
|
1137
1137
|
}
|
|
1138
|
+
#editor-x .rounded-t-xl {
|
|
1139
|
+
border-top-left-radius: var(--radius-xl);
|
|
1140
|
+
border-top-right-radius: var(--radius-xl);
|
|
1141
|
+
}
|
|
1138
1142
|
#editor-x .rounded-b-xl {
|
|
1139
1143
|
border-bottom-right-radius: var(--radius-xl);
|
|
1140
1144
|
border-bottom-left-radius: var(--radius-xl);
|
|
@@ -1262,10 +1266,10 @@
|
|
|
1262
1266
|
background-color: color-mix(in oklab, var(--background) 95%, transparent);
|
|
1263
1267
|
}
|
|
1264
1268
|
}
|
|
1265
|
-
#editor-x .bg-black\/
|
|
1266
|
-
background-color: color-mix(in srgb, #000
|
|
1269
|
+
#editor-x .bg-black\/10 {
|
|
1270
|
+
background-color: color-mix(in srgb, #000 10%, transparent);
|
|
1267
1271
|
@supports (color: color-mix(in lab, red, red)) {
|
|
1268
|
-
background-color: color-mix(in oklab, var(--color-black)
|
|
1272
|
+
background-color: color-mix(in oklab, var(--color-black) 10%, transparent);
|
|
1269
1273
|
}
|
|
1270
1274
|
}
|
|
1271
1275
|
#editor-x .bg-black\/60 {
|
|
@@ -1328,12 +1332,6 @@
|
|
|
1328
1332
|
background-color: color-mix(in oklab, var(--muted) 20%, transparent);
|
|
1329
1333
|
}
|
|
1330
1334
|
}
|
|
1331
|
-
#editor-x .bg-muted\/30 {
|
|
1332
|
-
background-color: var(--muted);
|
|
1333
|
-
@supports (color: color-mix(in lab, red, red)) {
|
|
1334
|
-
background-color: color-mix(in oklab, var(--muted) 30%, transparent);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
1335
|
#editor-x .bg-muted\/40 {
|
|
1338
1336
|
background-color: var(--muted);
|
|
1339
1337
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1527,12 +1525,12 @@
|
|
|
1527
1525
|
#editor-x .pt-0 {
|
|
1528
1526
|
padding-top: calc(var(--spacing) * 0);
|
|
1529
1527
|
}
|
|
1528
|
+
#editor-x .pt-3 {
|
|
1529
|
+
padding-top: calc(var(--spacing) * 3);
|
|
1530
|
+
}
|
|
1530
1531
|
#editor-x .pt-4 {
|
|
1531
1532
|
padding-top: calc(var(--spacing) * 4);
|
|
1532
1533
|
}
|
|
1533
|
-
#editor-x .pt-5 {
|
|
1534
|
-
padding-top: calc(var(--spacing) * 5);
|
|
1535
|
-
}
|
|
1536
1534
|
#editor-x .pt-6 {
|
|
1537
1535
|
padding-top: calc(var(--spacing) * 6);
|
|
1538
1536
|
}
|
|
@@ -1542,6 +1540,9 @@
|
|
|
1542
1540
|
#editor-x .pr-10 {
|
|
1543
1541
|
padding-right: calc(var(--spacing) * 10);
|
|
1544
1542
|
}
|
|
1543
|
+
#editor-x .pr-12 {
|
|
1544
|
+
padding-right: calc(var(--spacing) * 12);
|
|
1545
|
+
}
|
|
1545
1546
|
#editor-x .pb-2 {
|
|
1546
1547
|
padding-bottom: calc(var(--spacing) * 2);
|
|
1547
1548
|
}
|
|
@@ -3879,4 +3880,4 @@
|
|
|
3879
3880
|
--tw-content: "";
|
|
3880
3881
|
}
|
|
3881
3882
|
}
|
|
3882
|
-
}
|
|
3883
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -2698,29 +2698,29 @@ function ImageComponent({
|
|
|
2698
2698
|
className: "max-w-[96vw] max-h-[96vh] w-[96vw] h-[96vh] overflow-hidden flex flex-col p-0 gap-0 rounded-xl border shadow-2xl",
|
|
2699
2699
|
"aria-describedby": "view-original-image-desc",
|
|
2700
2700
|
children: [
|
|
2701
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHeader, { className: "shrink-0 px-
|
|
2701
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHeader, { className: "shrink-0 px-4 pt-3 pb-3 pr-12 border-b border-border/50 bg-muted/20 rounded-t-xl", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogTitle, { className: "text-sm font-semibold", children: "Xem h\xECnh g\u1ED1c" }) }),
|
|
2702
2702
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2703
2703
|
"div",
|
|
2704
2704
|
{
|
|
2705
2705
|
id: "view-original-image-desc",
|
|
2706
|
-
className: "flex-1 min-h-
|
|
2706
|
+
className: "flex-1 min-h-0 overflow-auto flex items-center justify-center p-4 bg-black/10",
|
|
2707
2707
|
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2708
2708
|
"img",
|
|
2709
2709
|
{
|
|
2710
2710
|
src,
|
|
2711
2711
|
alt: altText || "H\xECnh g\u1ED1c",
|
|
2712
|
-
className: "
|
|
2712
|
+
className: "max-w-full max-h-full w-auto h-auto object-contain rounded-lg select-none"
|
|
2713
2713
|
}
|
|
2714
2714
|
)
|
|
2715
2715
|
}
|
|
2716
2716
|
),
|
|
2717
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogFooter, { className: "shrink-0 flex-row justify-center gap-2 px-
|
|
2717
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogFooter, { className: "shrink-0 flex-row justify-center gap-2 px-4 py-3 border-t border-border/50 bg-muted/20 rounded-b-xl", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2718
2718
|
Button,
|
|
2719
2719
|
{
|
|
2720
2720
|
variant: "outline",
|
|
2721
|
-
size: "
|
|
2721
|
+
size: "sm",
|
|
2722
2722
|
asChild: true,
|
|
2723
|
-
className: "gap-2
|
|
2723
|
+
className: "gap-2",
|
|
2724
2724
|
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
2725
2725
|
"a",
|
|
2726
2726
|
{
|