Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ Format dựa trên [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Maj

## [Unreleased]

### Changed (BREAKING for consumers)

- Remove `@sdcorejs/angular/components/chart` and its `SdLineChartComponent`, `SdBarChartComponent`, `SdPieChartComponent`, and `SdDoughnutChartComponent` exports (also removed from the root/components barrels). Chart.js is no longer a Core UI dependency; consumers choose, install, and configure their own chart library. `sd-org-chart` remains available.

Migration: remove the Core UI chart imports and replace `<sd-line-chart>`, `<sd-bar-chart>`, `<sd-pie-chart>`, and `<sd-doughnut-chart>` in consumer templates. If retaining Chart.js, declare `chart.js` as a direct application dependency and own its canvas lifecycle and registration:

```diff
- import { SdLineChartComponent } from '@sdcorejs/angular/components/chart';
- // Component imports: [SdLineChartComponent]
+ import { Chart, registerables } from 'chart.js'; // installed by the consumer
+ Chart.register(...registerables);
+ // Create a Chart on the application's canvas and destroy it during teardown.
```

### Added

- Sidebar V3 supports independent expand/collapse of menu groups at every depth, with keyboard-accessible disclosure buttons. Group state survives search and sidebar rail toggles; navigation opens the active branch, and selecting a group icon in the rail opens that group.
- Form builder groups support `properties.collapsible` (default `false`), matching `sd-section`. Enable it to expand/collapse groups in preview and form render while preserving child values and validation. Group conditions remain limited to visibility; disabled-when rules belong to child fields.

### Fixed

- Table row-command children and selection-action menus use a compact white CDK menu with 36px rows, 18px icons and 8px corners. Preserve child filtering, disabled commands, callbacks, keyboard navigation, focus restoration and overlay placement outside clipped cells; touch targets remain 44px.
- Side drawer, dialog and bottom-sheet headers/footers share a white background and use compact 12px vertical and 16px horizontal padding. Body content also uses `12px 16px` padding on desktop and mobile, including its own top spacing below the separate header surface; mobile safe-area spacing and touch targets remain supported.
- Tab group pills clip hover/ripple effects to their rounded shape and retain the active fill on hover. Segmented tabs have a 4px gap so adjacent hover backgrounds remain separate.
- Hover-copy confirmation tooltips render in a CDK overlay above table rows and outside clipped cells. Scrolling, disabling and teardown clean up the overlay; initial rendering creates only one copy button.
- Query builder's add-condition/group menu renders outside ancestor overflow, keeping both actions visible in short modal bodies. Backdrop/Escape dismissal and focus restoration keep the surrounding modal open.

## [2.8] - 2026-09-11

Release suffix `2.8` targets `19.2.8`, `20.2.8`, `21.2.8`, and `22.2.8`.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

| Area | What the library provides |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| UI components | Navigation/data state, PDF preview, job progress, audit diff, modals, drawers, tabs, charts, and editors |
| UI components | Navigation/data state, PDF preview, job progress, audit diff, modals, drawers, tabs, and editors |
| Data and workflow | Local/server tables, query builders, entity/tree pickers, unsaved-change guards, background tasks, file upload, and Excel import |
| Form controls | Text/mask, number, time/time range, date/date range, datetime, select, autocomplete, checkbox, radio, switch, chip, color, and inline text |
| Application services | Typed API/retry/cancel, ref-counted loading, graph-safe storage/cache/persistence, viewport signals, notifications, and Excel |
Expand Down
6 changes: 4 additions & 2 deletions README.npm.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,20 @@ Replace the timer with your typed service call and reset `saving` in a `finally`

| Area | Representative APIs |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| UI components | Navigation/data state, PDF preview, job progress, audit diff, modals, drawers, tabs, charts, editors, and document tooling |
| UI components | Navigation/data state, PDF preview, job progress, audit diff, modals, drawers, tabs, editors, and document tooling |
| Data and workflow | Local/server tables, entity/tree pickers, query builders, unsaved-change guards, background tasks, upload, and Excel import |
| Form controls | Text/mask, number, time/time range, date/date range, datetime, select, autocomplete, checkbox, radio, switch, chip, and color |
| Services | Typed API/retry/cancel, ref-counted loading, graph-safe persistence/cache/storage, viewport signals, notifications, and exports |
| Portal modules | Auth, Keycloak, permission, layout, and icon modules |
| Localization | Built-in `vi`, `en`, `ja`, `ko`, and `zh` catalogs, plus a synchronous custom-catalog provider |

Charting libraries are selected, installed, and configured by the consuming application. Core UI does not bundle a chart engine; `sd-org-chart` remains available for organizational hierarchies.

The [live showcase](https://sdcorejs.github.io/sdcorejs-angular/) demonstrates components, forms, and services. The [latest API manifest](https://sdcorejs.github.io/sdcorejs-angular/docs/latest/index.json) lists every published reference document without duplicating the full API here.

## Standalone and subpath imports

Prefer public leaf entry points so dependencies stay explicit and unused entry points can be removed from the application graph. The package declares `sideEffects: false`.
Prefer public leaf entry points so dependencies stay explicit and unused entry points can be removed from the application graph. Stylesheets and editor registration entry points are retained as side effects.

```ts
import { SdButton } from '@sdcorejs/angular/components/button';
Expand Down
5 changes: 3 additions & 2 deletions scripts/generate-showcase-route-shells.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ test('matches the canonical v19 runtime registry and expected deployment route c
.map(category => [category, pages.filter(page => page.category === category).length])
);

assert.equal(pages.length, 99);
assert.equal(pages.length, 98);
assert.ok(!pages.some(page => page.category === 'components' && page.slug === 'chart'));
assert.ok(pages.some(page => page.category === 'pipes-utilities' && page.slug === 'read-state'));

// why: `routes.length` từng là hằng số 5941 và đã mục ngay khi release 1.6 ra (thực tế 7426).
Expand All @@ -201,7 +202,7 @@ test('matches the canonical v19 runtime registry and expected deployment route c
'total = 1 root redirect + one identical block per release'
);
assert.deepEqual(categoryCounts, {
components: 37,
components: 36,
directives: 6,
forms: 22,
guides: 3,
Expand Down
1 change: 0 additions & 1 deletion scripts/lint-phase.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const phasePaths = {
'projects/sdcorejs-angular/components/avatar',
'projects/sdcorejs-angular/components/badge',
'projects/sdcorejs-angular/components/button',
'projects/sdcorejs-angular/components/chart',
],
'components-editor': [
'projects/sdcorejs-angular/components/ckeditor-styles',
Expand Down
19 changes: 0 additions & 19 deletions showcase/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion showcase/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"@lucide/angular": "^1.22.0",
"@sdcorejs/angular-material-datetime": "1.0.4",
"@sdcorejs/utils": "1.1.4",
"chart.js": "^4.5.1",
"ckeditor5": "48.0.0",
"date-fns": "^3.6.0",
"exceljs": "^4.4.0",
Expand Down
13 changes: 7 additions & 6 deletions showcase/src/app/docs/core/documentation.registry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SHOWCASE_EXAMPLE_SOURCES } from '../generated/example-sources.generated

const EXPECTED_CATEGORY_COUNTS = {
guides: 3,
components: 37,
components: 36,
forms: 22,
directives: 6,
services: 11,
Expand All @@ -17,14 +17,15 @@ describe('documentation registry', () => {
const publishedIds = DOC_PAGES.map(page => page.publishedDocId).filter(id => id !== null);
const localOnlyPages = DOC_PAGES.filter(page => page.publishedDocId === null);

expect(DOC_PAGES).toHaveSize(99);
expect(new Set(publishedIds).size).toBe(99);
expect(DOC_PAGES).toHaveSize(98);
expect(new Set(publishedIds).size).toBe(98);
expect(DOC_PAGES.some(page => page.category === 'components' && page.slug === 'chart')).toBeFalse();
expect(localOnlyPages).toHaveSize(0);
expect(DOC_CATEGORIES).toHaveSize(7);
for (const category of DOC_CATEGORIES) {
expect(getDocPagesByCategory(category)).withContext(category).toHaveSize(EXPECTED_CATEGORY_COUNTS[category]);
}
expect(DOC_PAGES.reduce((total, page) => total + page.demoSectionCount, 0)).toBe(360);
expect(DOC_PAGES.reduce((total, page) => total + page.demoSectionCount, 0)).toBe(357);
});

it('uses unique stable page ids and category/slug pairs', () => {
Expand All @@ -46,7 +47,7 @@ describe('documentation registry', () => {
const exampleIds = DOC_PAGES.flatMap(page => page.examples.map(example => example.id));

expect(new Set(exampleIds).size).toBe(exampleIds.length);
expect(exampleIds).toHaveSize(360);
expect(exampleIds).toHaveSize(357);
expect(findDocPage('components', 'table')?.examples.map(example => example.sectionId)).toContain('example-quick-search');
expect(findDocPage('components', 'table')?.examples.map(example => example.sectionId)).toContain('example-external-filters');
for (const page of DOC_PAGES) {
Expand All @@ -61,7 +62,7 @@ describe('documentation registry', () => {
});

it('derives navigation groups and canonical/legacy lookup helpers from the registry', () => {
expect(DOC_NAV_GROUPS.map(group => group.pages.length)).toEqual([3, 37, 22, 6, 11, 10, 10]);
expect(DOC_NAV_GROUPS.map(group => group.pages.length)).toEqual([3, 36, 22, 6, 11, 10, 10]);
expect(findDocPage('components', 'button')?.title).toBe('Button');
expect(findDocPage('directives', 'tooltip')?.publishedDocId).toBe('directives/src/sd-tooltip');
expect(findDocPage('components', 'generic')?.title).toBe('Form Generic');
Expand Down
13 changes: 0 additions & 13 deletions showcase/src/app/docs/core/documentation.registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,6 @@ const COMPONENT_PAGES = [
demoSectionCount: 3,
loadComponent: () => import('../../pages/components/breadcrumb/breadcrumb-demo.component').then(m => m.BreadcrumbDemoComponent),
}),
defineDocPage({
category: 'components',
slug: 'chart',
title: 'Chart',
description: 'Biểu đồ Chart.js cho dashboard và báo cáo: line, bar, pie và doughnut.',
selector: 'sd-line-chart, sd-bar-chart, sd-pie-chart, sd-doughnut-chart',
importPath: '@sdcorejs/angular/components/chart',
publishedDocId: 'components/chart/sd-chart',
keywords: ['chart.js', 'dashboard', 'report', 'visualization'],
status: 'stable',
demoSectionCount: 3,
loadComponent: () => import('../../pages/components/chart/chart-demo.component').then(m => m.ChartDemoComponent),
}),
defineDocPage({
category: 'components',
slug: 'code-editor',
Expand Down
30 changes: 3 additions & 27 deletions showcase/src/app/docs/generated/example-manifest.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ export type ShowcaseExampleSourceKey =
| "components/card/example-object-comparewith"
| "components/card/example-single-selection"
| "components/card/example-standalone-card"
| "components/chart/example-bieu-do-bar"
| "components/chart/example-bieu-do-line"
| "components/chart/example-bieu-do-pie-doughnut"
| "components/code-editor/example-che-do-xem-json"
| "components/code-editor/example-ngon-ngu-html"
| "components/code-editor/example-ngon-ngu-typescript"
Expand Down Expand Up @@ -694,27 +691,6 @@ export const SHOWCASE_EXAMPLE_MANIFEST = [
title: "Disabled và color",
description: "Gồm selected+disabled, group disabled, inherited color, override color và standalone selected state.",
},
{
sourceKey: "components/chart/example-bieu-do-line",
pageKey: "components/chart",
sectionId: "example-bieu-do-line",
title: "Biểu đồ Line",
description: "Existing “Biểu đồ Line” scenario preserved from the showcase.",
},
{
sourceKey: "components/chart/example-bieu-do-bar",
pageKey: "components/chart",
sectionId: "example-bieu-do-bar",
title: "Biểu đồ Bar",
description: "Existing “Biểu đồ Bar” scenario preserved from the showcase.",
},
{
sourceKey: "components/chart/example-bieu-do-pie-doughnut",
pageKey: "components/chart",
sectionId: "example-bieu-do-pie-doughnut",
title: "Biểu đồ Pie & Doughnut",
description: "Existing “Biểu đồ Pie & Doughnut” scenario preserved from the showcase.",
},
{
sourceKey: "components/code-editor/example-ngon-ngu-typescript",
pageKey: "components/code-editor",
Expand Down Expand Up @@ -804,7 +780,7 @@ export const SHOWCASE_EXAMPLE_MANIFEST = [
pageKey: "components/form-generic",
sectionId: "example-builder-render",
title: "Builder + Render",
description: "Existing “Builder + Render” scenario preserved from the showcase.",
description: "Group có thể thu gọn/mở rộng trong preview; điều kiện vô hiệu hóa được cấu hình trên từng trường con.",
},
{
sourceKey: "components/history/example-luong-phe-duyet",
Expand Down Expand Up @@ -1574,7 +1550,7 @@ export const SHOWCASE_EXAMPLE_MANIFEST = [
pageKey: "components/table",
sectionId: "example-lenh-dong-co-menu-con",
title: "Lệnh dòng có menu con",
description: "Command children sẽ render thành nút menu; các child command vẫn hỗ trợ icon, title, color, disabled, hidden và click theo từng row.",
description: "Command và action children dùng menu gọn nền trắng. Chọn dòng để thử action nhóm; các child command vẫn hỗ trợ icon, title, color, disabled, hidden và click theo từng row.",
},
{
sourceKey: "components/table/example-keo-tha-doi-thu-tu",
Expand Down Expand Up @@ -2512,7 +2488,7 @@ export const SHOWCASE_EXAMPLE_MANIFEST = [
pageKey: "modules/layout",
sectionId: "example-sidebar-v3-collapsible",
title: "Sidebar V3 - Collapsible",
description: "Root icons, text-only nested branches and a compact search field on desktop; shared pinned and recent menus.",
description: "Bấm từng nhóm menu để đóng/mở các mục con trên desktop. Tìm kiếm vẫn thấy mục trong nhóm đã đóng; thu gọn cả sidebar giữ trạng thái từng nhóm.",
},
{
sourceKey: "pipes-utilities/empty/example-gia-tri-rong-hien-thi-dau-gach",
Expand Down
Loading
Loading