@thangph2146/nextjs-editor 1.0.9 → 1.0.10
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 +3 -21
- package/dist/editor-utilities-raw.css +1 -10
- package/dist/editor-utilities-scoped.css +1 -10
- package/dist/index.cjs +23 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -50
- package/dist/index.js.map +1 -1
- package/dist/styles.css +797 -851
- package/package.json +89 -90
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, scope trong `#editor-x` và
|
|
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` và **không bọc trong @layer** (unlayered). Để style editor không bị SCSS app ghi đè, nên import `styles.css` sau cùng (sau globals và SCSS của app).
|
|
30
30
|
|
|
31
31
|
### 2. Dùng component Editor (Client Component)
|
|
32
32
|
|
|
@@ -66,19 +66,7 @@ export function MyEditor() {
|
|
|
66
66
|
|
|
67
67
|
## Tránh SCSS/CSS của app ghi đè editor
|
|
68
68
|
|
|
69
|
-
Style editor được bọc trong
|
|
70
|
-
|
|
71
|
-
**Cách làm:** Đưa toàn bộ SCSS/global của app vào một layer (ví dụ `app`) và khai báo thứ tự layer sao cho `nextjs-editor` đứng **sau** — khi đó style editor sẽ thắng khi specificity tương đương.
|
|
72
|
-
|
|
73
|
-
### Bước 1: 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: Đưa SCSS/global vào layer `app`
|
|
69
|
+
Style editor được build **không bọc trong @layer** (unlayered). **Nên import `@thangph2146/nextjs-editor/styles.css` sau cùng** trong `layout.tsx` (sau globals và SCSS của app) để style editor có thứ tự load sau và dễ thắng khi specificity ngang nhau. App có thể ghi đè style editor nếu dùng selector cùng hoặc cao hơn specificity (vd. trùng `#editor-x` hoặc class trong scope).
|
|
82
70
|
|
|
83
71
|
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
72
|
|
|
@@ -110,7 +98,7 @@ Tạo file `src/app/globals-app.css`:
|
|
|
110
98
|
|
|
111
99
|
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
100
|
|
|
113
|
-
Sau khi cấu hình, style
|
|
101
|
+
Sau khi cấu hình (nếu dùng), style editor (đã load khi import `@thangph2146/nextjs-editor/styles.css`) có thứ tự sau SCSS trong `@layer app`; cấu trúc Tailwind và theme của editor trong `#editor-x` có thể bị app ghi đè nếu selector app có specificity cao hơn.
|
|
114
102
|
|
|
115
103
|
## Cấu hình API thư viện ảnh
|
|
116
104
|
|
|
@@ -289,12 +277,6 @@ pnpm build
|
|
|
289
277
|
npm publish --access public
|
|
290
278
|
```
|
|
291
279
|
|
|
292
|
-
**Nếu bật 2FA (one-time password):** thêm mã OTP từ app xác thực (đổi mỗi ~30s):
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
npm publish --access public --otp=XXXXXX
|
|
296
|
-
```
|
|
297
|
-
|
|
298
280
|
Nếu đã publish public trước đó, chỉ cần:
|
|
299
281
|
|
|
300
282
|
```bash
|
|
@@ -1812,10 +1812,6 @@
|
|
|
1812
1812
|
--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1813
1813
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1814
1814
|
}
|
|
1815
|
-
.shadow-none {
|
|
1816
|
-
--tw-shadow: 0 0 #0000;
|
|
1817
|
-
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1818
|
-
}
|
|
1819
1815
|
.shadow-sm {
|
|
1820
1816
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1821
1817
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -2892,11 +2888,6 @@
|
|
|
2892
2888
|
padding-block: calc(var(--spacing) * 6);
|
|
2893
2889
|
}
|
|
2894
2890
|
}
|
|
2895
|
-
.sm\:text-center {
|
|
2896
|
-
@media (width >= 40rem) {
|
|
2897
|
-
text-align: center;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
2891
|
.sm\:text-left {
|
|
2901
2892
|
@media (width >= 40rem) {
|
|
2902
2893
|
text-align: left;
|
|
@@ -3889,4 +3880,4 @@
|
|
|
3889
3880
|
--tw-content: "";
|
|
3890
3881
|
}
|
|
3891
3882
|
}
|
|
3892
|
-
}
|
|
3883
|
+
}
|
|
@@ -1812,10 +1812,6 @@
|
|
|
1812
1812
|
--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1813
1813
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1814
1814
|
}
|
|
1815
|
-
#editor-x .shadow-none {
|
|
1816
|
-
--tw-shadow: 0 0 #0000;
|
|
1817
|
-
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1818
|
-
}
|
|
1819
1815
|
#editor-x .shadow-sm {
|
|
1820
1816
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1821
1817
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -2892,11 +2888,6 @@
|
|
|
2892
2888
|
padding-block: calc(var(--spacing) * 6);
|
|
2893
2889
|
}
|
|
2894
2890
|
}
|
|
2895
|
-
#editor-x .sm\:text-center {
|
|
2896
|
-
@media (width >= 40rem) {
|
|
2897
|
-
text-align: center;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
2891
|
#editor-x .sm\:text-left {
|
|
2901
2892
|
@media (width >= 40rem) {
|
|
2902
2893
|
text-align: left;
|
|
@@ -3889,4 +3880,4 @@
|
|
|
3889
3880
|
--tw-content: "";
|
|
3890
3881
|
}
|
|
3891
3882
|
}
|
|
3892
|
-
}
|
|
3883
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -2123,17 +2123,12 @@ function ContentEditable({
|
|
|
2123
2123
|
placeholder: placeholder2,
|
|
2124
2124
|
className,
|
|
2125
2125
|
placeholderClassName,
|
|
2126
|
-
placeholderDefaults = true
|
|
2127
|
-
readOnly = false
|
|
2126
|
+
placeholderDefaults = true
|
|
2128
2127
|
}) {
|
|
2129
2128
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2130
2129
|
import_LexicalContentEditable.ContentEditable,
|
|
2131
2130
|
{
|
|
2132
|
-
className: cn(
|
|
2133
|
-
"ContentEditable__root relative block px-8 py-4 focus:outline-none",
|
|
2134
|
-
readOnly ? "min-h-0" : "min-h-72",
|
|
2135
|
-
className
|
|
2136
|
-
),
|
|
2131
|
+
className: cn("ContentEditable__root relative block min-h-72 px-8 py-4 focus:outline-none", className),
|
|
2137
2132
|
"aria-placeholder": placeholder2,
|
|
2138
2133
|
"aria-label": placeholder2 || "Editor n\u1ED9i dung",
|
|
2139
2134
|
placeholder: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
@@ -2622,39 +2617,20 @@ function ImageComponent({
|
|
|
2622
2617
|
e.stopPropagation();
|
|
2623
2618
|
setIsViewOriginalOpen(true);
|
|
2624
2619
|
}, [isEditable]);
|
|
2625
|
-
const imageWrapper = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2626
|
-
|
|
2620
|
+
const imageWrapper = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { draggable, children: isLoadError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(BrokenImage, {}) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2621
|
+
LazyImage,
|
|
2627
2622
|
{
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
}
|
|
2638
|
-
},
|
|
2639
|
-
style: { cursor: "pointer", pointerEvents: "auto" },
|
|
2640
|
-
className: "block w-full"
|
|
2641
|
-
},
|
|
2642
|
-
children: isLoadError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(BrokenImage, {}) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2643
|
-
LazyImage,
|
|
2644
|
-
{
|
|
2645
|
-
className: imageClassName,
|
|
2646
|
-
src,
|
|
2647
|
-
altText,
|
|
2648
|
-
imageRef,
|
|
2649
|
-
width: responsiveDimensions.width,
|
|
2650
|
-
height: responsiveDimensions.height,
|
|
2651
|
-
maxWidth,
|
|
2652
|
-
onError: () => setIsLoadError(true),
|
|
2653
|
-
fetchPriority: isPriority ? "high" : "auto"
|
|
2654
|
-
}
|
|
2655
|
-
)
|
|
2623
|
+
className: imageClassName,
|
|
2624
|
+
src,
|
|
2625
|
+
altText,
|
|
2626
|
+
imageRef,
|
|
2627
|
+
width: responsiveDimensions.width,
|
|
2628
|
+
height: responsiveDimensions.height,
|
|
2629
|
+
maxWidth,
|
|
2630
|
+
onError: () => setIsLoadError(true),
|
|
2631
|
+
fetchPriority: isPriority ? "high" : "auto"
|
|
2656
2632
|
}
|
|
2657
|
-
);
|
|
2633
|
+
) });
|
|
2658
2634
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2659
2635
|
import_react11.Suspense,
|
|
2660
2636
|
{
|
|
@@ -2671,8 +2647,7 @@ function ImageComponent({
|
|
|
2671
2647
|
{
|
|
2672
2648
|
type: "button",
|
|
2673
2649
|
onClick: handleViewOriginal,
|
|
2674
|
-
className: "
|
|
2675
|
-
style: { pointerEvents: "auto" },
|
|
2650
|
+
className: "cursor-pointer border-0 bg-transparent p-0 text-left outline-none [&>div]:outline-none",
|
|
2676
2651
|
"aria-label": "Xem h\xECnh g\u1ED1c",
|
|
2677
2652
|
children: imageWrapper
|
|
2678
2653
|
}
|
|
@@ -2723,20 +2698,20 @@ function ImageComponent({
|
|
|
2723
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",
|
|
2724
2699
|
"aria-describedby": "view-original-image-desc",
|
|
2725
2700
|
children: [
|
|
2726
|
-
/* @__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
|
|
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" }) }),
|
|
2727
2702
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2728
2703
|
"div",
|
|
2729
2704
|
{
|
|
2730
2705
|
id: "view-original-image-desc",
|
|
2731
|
-
className: "flex-1 min-h-0
|
|
2732
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2706
|
+
className: "flex-1 min-h-0 overflow-auto flex items-center justify-center p-4 bg-black/10",
|
|
2707
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2733
2708
|
"img",
|
|
2734
2709
|
{
|
|
2735
2710
|
src,
|
|
2736
2711
|
alt: altText || "H\xECnh g\u1ED1c",
|
|
2737
|
-
className: "
|
|
2712
|
+
className: "max-w-full max-h-full w-auto h-auto object-contain rounded-lg select-none"
|
|
2738
2713
|
}
|
|
2739
|
-
)
|
|
2714
|
+
)
|
|
2740
2715
|
}
|
|
2741
2716
|
),
|
|
2742
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)(
|
|
@@ -33235,8 +33210,7 @@ function Plugins({
|
|
|
33235
33210
|
ContentEditable,
|
|
33236
33211
|
{
|
|
33237
33212
|
placeholder: readOnly ? "" : placeholder,
|
|
33238
|
-
readOnly
|
|
33239
|
-
className: readOnly ? "cursor-default select-text border-0 bg-transparent shadow-none" : ""
|
|
33213
|
+
className: `ContentEditable__root relative block min-h-72 px-8 py-4 focus:outline-none ${readOnly ? "cursor-default select-text border border-border rounded-md" : ""}`
|
|
33240
33214
|
}
|
|
33241
33215
|
) }) }),
|
|
33242
33216
|
ErrorBoundary: import_LexicalErrorBoundary2.LexicalErrorBoundary,
|
|
@@ -33412,11 +33386,10 @@ function Editor({
|
|
|
33412
33386
|
{
|
|
33413
33387
|
ref: editorRef,
|
|
33414
33388
|
className: cn(
|
|
33415
|
-
"
|
|
33416
|
-
readOnly
|
|
33389
|
+
"w-full min-w-0",
|
|
33390
|
+
!readOnly && "bg-background rounded-lg shadow"
|
|
33417
33391
|
),
|
|
33418
33392
|
id: "editor-x",
|
|
33419
|
-
"data-readonly": readOnly ? "true" : void 0,
|
|
33420
33393
|
children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(EditorContainerProvider, { value: { maxWidth: editorMaxWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
|
|
33421
33394
|
import_LexicalComposer.LexicalComposer,
|
|
33422
33395
|
{
|