npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@libs-ui/components-inputs-quill2x-preview

v0.2.357-4

Published

> Component hiển thị nội dung Rich Text HTML từ trình soạn thảo Quill2x một cách an toàn, với tính năng Xem thêm / Thu gọn thông minh.

Downloads

2,077

Readme

@libs-ui/components-inputs-quill2x-preview

Component hiển thị nội dung Rich Text HTML từ trình soạn thảo Quill2x một cách an toàn, với tính năng Xem thêm / Thu gọn thông minh.

Giới thiệu

@libs-ui/components-inputs-quill2x-preview là component chuyên dụng để render nội dung HTML được tạo ra bởi trình soạn thảo Quill2x. Component tự động sanitize nội dung qua LibsUiPipesSecurityTrustPipe để ngăn chặn XSS, đồng thời hỗ trợ cơ chế thu gọn / mở rộng thông minh khi nội dung quá dài. Styling được kế thừa từ Quill Snow theme đảm bảo nội dung hiển thị nhất quán với trình soạn thảo.

Tính năng

  • Hiển thị nhất quán — Kế thừa Quill Snow theme styles, đảm bảo nội dung render giống hệt trình soạn thảo
  • Bảo mật XSS — Tự động sanitize HTML qua LibsUiPipesSecurityTrustPipe với useXssFilter: true
  • Xem thêm / Thu gọn — Tự động phát hiện nội dung vượt maxHeight, hiển thị nút điều khiển và hiệu ứng gradient mờ
  • Two-way bindingexpandmodel() hỗ trợ kiểm soát trạng thái mở rộng từ bên ngoài
  • Custom class — Cho phép truyền thêm CSS class vào container qua containerClass
  • Label tùy biến — Nhãn nút Xem thêm / Thu gọn có thể tùy chỉnh hoặc dùng i18n key mặc định
  • PerformanceChangeDetectionStrategy.OnPush + Signal API tối ưu hiệu năng render

Khi nào sử dụng

  • Khi cần hiển thị nội dung được tạo ra bởi trình soạn thảo Quill2x (rich text, HTML)
  • Khi cần render HTML từ API một cách an toàn mà không lo XSS
  • Khi muốn giới hạn không gian hiển thị cho bài viết dài trong danh sách hoặc feed
  • Khi cần hiển thị preview nội dung email, mô tả sản phẩm, bài viết blog có định dạng phong phú

Cài đặt

npm install @libs-ui/components-inputs-quill2x-preview

Import

import { LibsUiComponentsInputsQuill2xPreviewComponent } from '@libs-ui/components-inputs-quill2x-preview';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsQuill2xPreviewComponent],
  // ...
})
export class YourComponent {}

Ví dụ sử dụng

Ví dụ 1 — Hiển thị cơ bản

// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsInputsQuill2xPreviewComponent } from '@libs-ui/components-inputs-quill2x-preview';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsQuill2xPreviewComponent],
  templateUrl: './article-detail.component.html',
})
export class ArticleDetailComponent {
  protected articleContent = signal<string>(
    '<h2>Tiêu đề bài viết</h2><p>Đây là nội dung bài viết với <strong>in đậm</strong> và <em>in nghiêng</em>.</p>'
  );
}
<!-- article-detail.component.html -->
<libs_ui-components-inputs-quill2x-preview
  [data]="articleContent()">
</libs_ui-components-inputs-quill2x-preview>

Ví dụ 2 — Xem thêm / Thu gọn cho nội dung dài

// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsInputsQuill2xPreviewComponent } from '@libs-ui/components-inputs-quill2x-preview';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsQuill2xPreviewComponent],
  templateUrl: './news-feed.component.html',
})
export class NewsFeedComponent {
  protected postContent = signal<string>(`
    <h3>Thông báo quan trọng</h3>
    <p>Đây là nội dung bài viết rất dài với nhiều đoạn văn...</p>
    <ul>
      <li>Điểm thứ nhất cần chú ý</li>
      <li>Điểm thứ hai cần chú ý</li>
      <li>Điểm thứ ba cần chú ý</li>
      <li>Điểm thứ tư cần chú ý</li>
      <li>Điểm thứ năm cần chú ý</li>
    </ul>
    <p>Kết luận của bài viết.</p>
  `);
  protected isExpanded = signal<boolean>(false);
}
<!-- news-feed.component.html -->
<libs_ui-components-inputs-quill2x-preview
  [data]="postContent()"
  [maxHeight]="120"
  [hasButtonCollapseExpand]="true"
  [labelButtonViewMore]="'Xem toàn bộ bài viết'"
  [labelButtonCollapse]="'Thu gọn bài viết'"
  [(expand)]="isExpanded()">
</libs_ui-components-inputs-quill2x-preview>

Ví dụ 3 — Tùy biến CSS class và kiểm soát expand từ bên ngoài

// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsInputsQuill2xPreviewComponent } from '@libs-ui/components-inputs-quill2x-preview';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsQuill2xPreviewComponent],
  templateUrl: './product-description.component.html',
})
export class ProductDescriptionComponent {
  protected description = signal<string>(
    '<p style="color: #ee2d41; font-size: 18px;"><strong>Sản phẩm nổi bật</strong></p><p>Mô tả chi tiết sản phẩm với nhiều thông tin hữu ích.</p>'
  );
  protected isOpen = signal<boolean>(false);

  protected handlerToggleExpand(event: Event): void {
    event.stopPropagation();
    this.isOpen.update((val) => !val);
  }
}
<!-- product-description.component.html -->
<button (click)="handlerToggleExpand($event)">
  {{ isOpen() ? 'Thu gọn' : 'Mở rộng' }}
</button>

<libs_ui-components-inputs-quill2x-preview
  [data]="description()"
  [containerClass]="'border border-gray-200 rounded p-2'"
  [maxHeight]="200"
  [hasButtonCollapseExpand]="true"
  [(expand)]="isOpen()">
</libs_ui-components-inputs-quill2x-preview>

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | data | string | (Required) | Chuỗi HTML cần hiển thị. Nội dung sẽ được tự động sanitize trước khi render | [data]="articleHtml()" | | containerClass | string | undefined | Class CSS bổ sung cho thẻ .ql-container bên trong. Dùng để override style hoặc thêm border/padding | [containerClass]="'border rounded p-2'" | | expand | boolean | undefined | Trạng thái mở rộng / thu gọn. Là model() — hỗ trợ two-way binding [(expand)] | [(expand)]="isExpanded()" | | hasButtonCollapseExpand | boolean | undefined (falsy) | Bật tính năng giới hạn chiều cao và nút Xem thêm / Thu gọn. Khi true, component đo chiều cao sau render | [hasButtonCollapseExpand]="true" | | maxHeight | number | 160 | Chiều cao tối đa tính bằng pixel trước khi kích hoạt nút Xem thêm. Nếu truyền undefined hoặc 0, mặc định về 160 | [maxHeight]="200" | | labelButtonViewMore | string | 'i18n_view_more' | Nhãn hiển thị trên nút Xem thêm. Nếu không truyền, dùng i18n key i18n_view_more | [labelButtonViewMore]="'Xem toàn bộ'" | | labelButtonCollapse | string | 'i18n_collapse' | Nhãn hiển thị trên nút Thu gọn. Nếu không truyền, dùng i18n key i18n_collapse | [labelButtonCollapse]="'Thu gọn lại'" |

Logic ngầm quan trọng

Tự động phát hiện nội dung dài

Khi hasButtonCollapseExpandtrue, trong ngAfterViewInit component dùng timer(250) chờ DOM render xong rồi so sánh offsetHeight của container với maxHeight + 28:

timer(250)
  .pipe(takeUntilDestroyed(this.destroyRef))
  .subscribe(() => {
    this.hasShowMore.set(
      this.previewRef().nativeElement.offsetHeight > this.maxHeight() + 28
    );
  });

Delay 250ms là cần thiết để Quill styles được áp dụng đầy đủ trước khi đo chiều cao. Nếu nội dung không vượt ngưỡng, nút Xem thêm không xuất hiện dù hasButtonCollapseExpand = true.

Hiệu ứng gradient fade

Khi nội dung bị thu gọn (hasShowMore() && !expand()), một lớp overlay gradient trắng được chèn tuyệt đối ở đáy container tạo hiệu ứng chuyển tiếp mượt mà:

<div class="absolute bottom-[28px] w-full h-[40px] opacity-[0.5]
  bg-[linear-gradient(180deg,rgba(255,255,255,0)_0%,rgba(255,255,255,0.95)_51.56%,#fff_100%)]">
</div>

CSS fix Quill 2.x list rendering

Component có SCSS override phức tạp để sửa lỗi đánh số tự động bị sai trong Quill 2.x khi xen kẽ giữa danh sách ordered và bullet. Sử dụng counter-resetcounter-increment tùy chỉnh thay vì dựa vào CSS mặc định của Quill.

Lưu ý quan trọng

⚠️ Sanitization tự động: Component dùng LibsUiPipesSecurityTrustPipe với useXssFilter: true để sanitize HTML. Không cần sanitize thủ công trước khi truyền vào [data].

⚠️ Quill CSS dependency: Component yêu cầu Quill Snow theme CSS được load trên trang để styles hiển thị đúng. Nếu không có, nội dung vẫn render nhưng có thể mất một số định dạng.

⚠️ maxHeight transform: Input maxHeight có transform — nếu truyền undefined hoặc 0, giá trị sẽ tự động về 160. Đây là hành vi có chủ đích để tránh container bị thu gọn về 0px.

⚠️ expand là model(): expand dùng model() thay vì input(). Sử dụng [(expand)] cho two-way binding. Nếu chỉ cần one-way, dùng [expand].

⚠️ hasButtonCollapseExpand + ngAfterViewInit: Nút Xem thêm chỉ hiển thị sau khi DOM render xong (sau 250ms). Không nên kiểm tra hasShowMore đồng bộ ngay khi component khởi tạo.

Demo

npx nx serve core-ui

Truy cập: http://localhost:4500/components/inputs/quill2x-preview