@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 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à nằm trong layer `nextjs-editor` nếu app dùng CSS layer cho SCSS/global (xem bên dưới), style editor sẽ không bị ghi đè.
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 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 **`@layer nextjs-editor`**. Trong CSS, rule **không nằm trong layer** (unlayered) độ ưu tiên cao hơn rule trong layer, nên nếu SCSS/global của app unlayered thì có thể ghi đè list, spacing, typography… bên trong `#editor-x`.
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 SCSS của app) để style editor thứ tự load sau 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 trong layer `nextjs-editor` (đã load khi import `@thangph2146/nextjs-editor/styles.css`) sẽ ưu tiên cao hơn layer `app`, nên cấu trúc Tailwind và theme của editor trong `#editor-x` không còn bị SCSS của app ghi đè.
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` thể bị app ghi đè nếu selector app 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
- "div",
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
- draggable,
2629
- ...!isEditable && {
2630
- role: "button",
2631
- tabIndex: 0,
2632
- onClick: handleViewOriginal,
2633
- onKeyDown: (e) => {
2634
- if (e.key === "Enter" || e.key === " ") {
2635
- e.preventDefault();
2636
- handleViewOriginal(e);
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: "block w-full cursor-pointer border-0 bg-transparent p-0 text-left outline-none [&>div]:outline-none",
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 text-center sm:text-center", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogTitle, { className: "text-sm font-semibold", children: "Xem h\xECnh g\u1ED1c" }) }),
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 w-full max-w-full overflow-x-hidden overflow-y-auto flex items-center justify-center p-4 bg-black/10",
2732
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "max-w-full max-h-full min-w-0 min-h-0 flex items-center justify-center", 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: "min-w-0 min-h-0 max-w-full max-h-full w-auto h-auto object-contain rounded-lg select-none"
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
- "bg-background rounded-lg w-full",
33416
- readOnly ? "shadow-none" : "shadow"
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
  {