easy-mat-ui-ng20 20.0.0 → 20.0.2

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
@@ -1,253 +1,275 @@
1
- # easy-mat-ui
2
-
3
- [![npm](https://img.shields.io/npm/v/easy-mat-ui-ng20.svg)](https://www.npmjs.com/package/easy-mat-ui-ng20)
4
- [![CI](https://github.com/chaibiredouane/easy-mat-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/chaibiredouane/easy-mat-ui/actions/workflows/ci.yml)
5
- [![Angular](https://img.shields.io/badge/Angular-20-dd0031.svg)](https://angular.dev)
6
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
-
8
- **[Live demo](__SITE_URL__/)** · **[Documentation](__SITE_URL__/docs/)** · [npm](https://www.npmjs.com/package/easy-mat-ui-ng20) · [Changelog](CHANGELOG.md)
9
-
10
- A set of customizable Angular Material components built around a configurable **data table**:
11
- filtering, sorting, pagination, typed columns, expandable rows, tabbed child tables, a toolbar,
12
- a configurable **create / edit / view dialog** and a **multi-select** control, with
13
- [ngx-translate](https://github.com/ngx-translate/core) based i18n.
14
-
15
- ## Features
16
-
17
- - `lib-easy-table` / `lib-easy-table-basic`: a Material table driven by a single `EasyTableConfig` object.
18
- - Typed columns (`MatColumnTyped`): text, number, date, date-time, icon, icon-and-text, button, dropdown list, image
19
- (flags), password and filter columns.
20
- - **Column filters** under the titles (a compact text input or a multi-select per column), global search, sorting,
21
- pagination, sticky columns and a header that stays pinned while the rows scroll.
22
- - Expandable rows with **child tables**, or several child tables in **tabs** (`childConfig`).
23
- - `EasyDialogService`: a configurable dialog to create, edit or view a record.
24
- - `lib-easy-multi-select`: a searchable multi-select with select-all, clear, read-only and compact modes.
25
- - **Light and dark themes** switchable at runtime (`EasyThemeService`), driven by CSS variables.
26
- - Responsive layout (tables adapt below 768 px and 1024 px) and no WCAG 2 A/AA violation reported by axe-core on the demo.
27
- - Shared models, enums and configuration classes exported from one entry point.
28
-
29
- ## Requirements and supported versions
30
-
31
- This package targets **Angular 20**. Each Angular major version has its own package so that applications
32
- are never forced to upgrade:
33
-
34
- | Angular | Package | Library version |
35
- |---|---|---|
36
- | 20 | `easy-mat-ui-ng20` | `20.x.x` |
37
- | 21 | `easy-mat-ui-ng21` | `21.x.x` (planned) |
38
-
39
- Peer dependencies: `@angular/core`, `@angular/common`, `@angular/forms`, `@angular/cdk`,
40
- `@angular/material`, `@angular/platform-browser` (all `^20.0.0`), `@ngx-translate/core` `^16`,
41
- `bootstrap` `^5`, `rxjs` `^7`. Optional: `@ngx-translate/http-loader`, `flag-icons` (country columns).
42
-
43
- ## Installation
44
-
45
- ```bash
46
- npm install easy-mat-ui-ng20
47
- ```
48
-
49
- Install the peer dependencies if your project does not have them yet:
50
-
51
- ```bash
52
- ng add @angular/material
53
- npm install @ngx-translate/core @ngx-translate/http-loader bootstrap
54
- ```
55
-
56
- The components use Material icons. `ng add @angular/material` normally takes care of it; otherwise add the
57
- font to your `index.html`:
58
-
59
- ```html
60
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
61
- ```
62
-
63
- ### Bundle size budget
64
-
65
- A new Angular project fails `ng build` in production with *"bundle initial exceeded maximum budget"* once Angular Material
66
- and this library are added: two components embed the Bootstrap stylesheet (a slimmer stylesheet is planned for 20.1). Raise the
67
- initial budget in `angular.json` (measured: about 1.9 MB raw, 254 kB transferred, for the quick start below):
68
-
69
- ```json
70
- "budgets": [
71
- { "type": "initial", "maximumWarning": "2.5MB", "maximumError": "4MB" }
72
- ]
73
- ```
74
-
75
- ## Quick start
76
-
77
- Provide ngx-translate once in your application config:
78
-
79
- ```typescript
80
- import { ApplicationConfig } from '@angular/core';
81
- import { provideTranslateService } from '@ngx-translate/core';
82
-
83
- export const appConfig: ApplicationConfig = {
84
- providers: [provideTranslateService({ defaultLanguage: 'en' })]
85
- };
86
- ```
87
-
88
- Use the table in a standalone component:
89
-
90
- ```typescript
91
- import { Component } from '@angular/core';
92
- import { EasyTableComponent, EasyTableConfig, MatColumnTyped } from 'easy-mat-ui-ng20';
93
-
94
- @Component({
95
- selector: 'app-users',
96
- standalone: true,
97
- imports: [EasyTableComponent],
98
- template: `<lib-easy-table [config]="config"></lib-easy-table>`
99
- })
100
- export class UsersComponent {
101
- config: Partial<EasyTableConfig> = {
102
- data: [
103
- { id: 1, name: 'Alice' },
104
- { id: 2, name: 'Bob' }
105
- ],
106
- displayedColumns: [
107
- new MatColumnTyped({ name: 'id' }),
108
- new MatColumnTyped({ name: 'name' })
109
- ],
110
- canCreate: true,
111
- canUpdate: true,
112
- canDelete: true
113
- };
114
- }
115
- ```
116
-
117
- Table events are exposed as outputs: `addItem`, `editItem`, `viewItem`, `deleteItem`, `customAction`,
118
- `clickField`, and more (see `EasyTableComponent`).
119
-
120
- ## Dialog example
121
-
122
- ```typescript
123
- import { inject } from '@angular/core';
124
- import { CRUD, EasyDialogService, MatColumnTyped } from 'easy-mat-ui-ng20';
125
-
126
- const dialog = inject(EasyDialogService);
127
-
128
- dialog.open({
129
- title: 'Edit user',
130
- pk: 'id',
131
- action: CRUD.UPDATE,
132
- data: { id: 1, name: 'Alice' },
133
- fields: [
134
- new MatColumnTyped({ name: 'id', order: 1 }),
135
- new MatColumnTyped({ name: 'name', order: 2, isRequired: true })
136
- ]
137
- }).afterClosed().subscribe(result => console.log(result?.event, result?.data));
138
- ```
139
-
140
- ## Demo application
141
-
142
- The repository contains a runnable demo in [`projects/demo`](projects/demo). It needs no backend: a mock service
143
- (`GeoService`) returns Observables like a real `HttpClient` service would, so replacing it is the only change a real
144
- application needs.
145
-
146
- ```bash
147
- git clone https://github.com/chaibiredouane/easy-mat-ui.git
148
- cd easy-mat-ui
149
- npm ci
150
- npm start # http://localhost:4200
151
- ```
152
-
153
- It shows what the library is for: **almost nothing to code**. Every page is four small files, in the same layout:
154
-
155
- | File | Role |
156
- |---|---|
157
- | `<page>.config.ts` | The whole configuration: columns, dialog fields, table options, tabs |
158
- | `<page>.html` | A few lines: `<lib-easy-table [config]="..." [childConfig]="...">` and its events |
159
- | `<page>.ts` | Loads data from the service and saves the dialog results |
160
- | `<page>.scss` | Page styles |
161
-
162
- Three pages, built on every country of the world (Algeria first) and their cities:
163
-
164
- 1. **Countries and their cities**: expandable rows; the child table is loaded when a row opens.
165
- 2. **Child tables in tabs**: `childConfig` as an array, one tab per configuration.
166
- 3. **Cities of any country**: one full table with header filters, flags, status icons and a complete
167
- add / edit / view / delete dialog.
168
-
169
- Each page has a *Show the code of this page* panel with its real source files, and the header has a
170
- Light / Dark / System theme switcher.
171
-
172
- Key points of the configuration:
173
-
174
- - `childConfig` takes one configuration, or an array to get tabs (`tabTitle`, `tabIcon`).
175
- - `isExpanded: true` on the parent adds the expand button; `extendRow` tells you which row opened.
176
- - `sortedBy: ''` keeps the order given by your service (the default sorts by text).
177
- - Rebuild a table configuration (a new `EasyTableConfig`) whenever its data changes.
178
-
179
- The demo data lives under `projects/demo/src/app/data` and is **not** part of the npm package. Countries and cities
180
- come from [GeoNames](https://www.geonames.org/) (CC BY 4.0), the administrative divisions of Algeria from Wikipedia
181
- (CC BY-SA 4.0): see `DATA-LICENSE.md` and `WORLD-DATA-SOURCES.md` in that folder. Populations are source values of varying
182
- years, not a census.
183
-
184
- ## Themes
185
-
186
- Light and dark themes are driven by CSS variables (`--text-color`, `--card-bg`, `--border-color`,
187
- `--color-primary-blue`, `--radius-md`, `--shadow-md`, ...), so an application can override them without touching the
188
- library. `EasyThemeService` switches theme at runtime, without reloading the page:
189
-
190
- ```typescript
191
- import { inject } from '@angular/core';
192
- import { EasyThemeService } from 'easy-mat-ui-ng20';
193
-
194
- const theme = inject(EasyThemeService);
195
- theme.setTheme('dark'); // 'light' | 'dark' | 'system' (follows the operating system, live)
196
- theme.toggle();
197
- theme.theme(); // the applied theme, as a signal
198
- ```
199
-
200
- The service does nothing until you call it, never stores anything unless you give it a `storageKey`
201
- (`EASY_THEME_OPTIONS`), and only adds the `dark-theme` class to `<body>` (the class the library stylesheet already
202
- used) and a `data-easy-theme` attribute on `<html>`. Applications that toggle `dark-theme` themselves keep working.
203
- Material components follow when your Angular Material theme uses `color-scheme` (for example `mat.theme`).
204
-
205
- ## Responsive and accessibility
206
-
207
- Below 768 px, tables size their columns to their content and scroll horizontally, and the sticky actions column shrinks
208
- to its buttons so the data stays visible. The demo is checked at 320, 375, 430, 768, 1024, 1440 and 1920 px in both
209
- themes (no horizontal overflow, no console error) and with axe-core (no WCAG 2 A/AA violation on the demo pages).
210
-
211
- ## Styles
212
-
213
- Components embed their own styles. To also get the shared classes (`green`, `red`, `taupe`, `bg-*`,
214
- spacing and Material overrides), add the stylesheet to the `styles` array of your `angular.json`:
215
-
216
- ```json
217
- "styles": [
218
- "node_modules/easy-mat-ui-ng20/styles/styles.scss",
219
- "node_modules/flag-icons/css/flag-icons.min.css"
220
- ]
221
- ```
222
-
223
- `flag-icons` is only needed for flag columns (`ColumnType.IMAGE` with a country code such as `fr`); its stylesheet is not bundled with the components.
224
-
225
- > **Troubleshooting:** with the Angular `application` builder, the `flag-icons` stylesheet can fail in
226
- > development with `Two output files share the same path but have different contents: media/xx.svg`.
227
- > Set `"outputHashing": "media"` in the `development` configuration of the `build` target of your
228
- > `angular.json`.
229
-
230
- ## Versioning
231
-
232
- The first number of the library version is the supported Angular major version (`20.x.x` supports
233
- Angular 20). The remaining numbers follow [Semantic Versioning](https://semver.org/):
234
- PATCH for bug fixes, MINOR for backward-compatible features, MAJOR for breaking changes within the
235
- same Angular line. See [CHANGELOG.md](CHANGELOG.md).
236
-
237
- ## Development
238
-
239
- ```bash
240
- npm ci
241
- npm start # runs the demo application
242
- npm run build # builds the library into dist/easy-mat-ui
243
- npm test # runs the unit tests (headless Chrome)
244
- ```
245
-
246
- ## Contributing
247
-
248
- Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and the
249
- [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities as described in [SECURITY.md](SECURITY.md).
250
-
251
- ## License
252
-
253
- [MIT](LICENSE)
1
+ # easy-mat-ui
2
+
3
+ [![npm](https://img.shields.io/npm/v/easy-mat-ui-ng20.svg)](https://www.npmjs.com/package/easy-mat-ui-ng20)
4
+ [![CI](https://github.com/chaibiredouane/easy-mat-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/chaibiredouane/easy-mat-ui/actions/workflows/ci.yml)
5
+ [![Angular](https://img.shields.io/badge/Angular-20-dd0031.svg)](https://angular.dev)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+
8
+ **[Live demo](__SITE_URL__/)** · **[Documentation](__SITE_URL__/docs/)** · [npm](https://www.npmjs.com/package/easy-mat-ui-ng20) · [Changelog](CHANGELOG.md)
9
+
10
+ A set of customizable Angular Material components built around a configurable **data table**:
11
+ filtering, sorting, pagination, typed columns, expandable rows, tabbed child tables, a toolbar,
12
+ a configurable **create / edit / view dialog** and a **multi-select** control, with
13
+ [ngx-translate](https://github.com/ngx-translate/core) based i18n.
14
+
15
+ ## Features
16
+
17
+ - `lib-easy-table` / `lib-easy-table-basic`: a Material table driven by a single `EasyTableConfig` object.
18
+ - Typed columns (`MatColumnTyped`): text, number, date, date-time, icon, icon-and-text, button, dropdown list, image
19
+ (flags), password and filter columns.
20
+ - **Column filters** under the titles (a compact text input or a multi-select per column), global search, sorting,
21
+ pagination, sticky columns and a header that stays pinned while the rows scroll.
22
+ - Expandable rows with **child tables**, or several child tables in **tabs** (`childConfig`).
23
+ - `EasyDialogService`: a configurable dialog to create, edit or view a record.
24
+ - `lib-easy-multi-select`: a searchable multi-select with select-all, clear, read-only and compact modes, or a single-choice dropdown (`single`).
25
+ - Reusable interface components, each with `@Input()` / `@Output()` and a typed model: `lib-easy-segmented`,
26
+ `lib-easy-chip-nav`, `lib-easy-language-switch`, `lib-easy-card` / `lib-easy-card-grid`, `lib-easy-stat` and
27
+ `lib-easy-page-header`.
28
+ - `npx easy-mat-ui add-page`: generates a page from these components and a table (see [Generate a page](#generate-a-page)).
29
+ - **Light and dark themes** switchable at runtime (`EasyThemeService`), driven by CSS variables.
30
+ - Responsive layout (tables adapt below 768 px and 1024 px) and no WCAG 2 A/AA violation reported by axe-core on the demo.
31
+ - Shared models, enums and configuration classes exported from one entry point.
32
+
33
+ ## Requirements and supported versions
34
+
35
+ This package targets **Angular 20**. Each Angular major version has its own package so that applications
36
+ are never forced to upgrade:
37
+
38
+ | Angular | Package | Library version |
39
+ |---|---|---|
40
+ | 20 | `easy-mat-ui-ng20` | `20.x.x` |
41
+ | 21 | `easy-mat-ui-ng21` | `21.x.x` (planned) |
42
+
43
+ Peer dependencies: `@angular/core`, `@angular/common`, `@angular/forms`, `@angular/cdk`,
44
+ `@angular/material`, `@angular/platform-browser` (all `^20.0.0`), `@ngx-translate/core` `^16`,
45
+ `bootstrap` `^5`, `rxjs` `^7`. Optional: `@ngx-translate/http-loader`, `flag-icons` (country columns).
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ npm install easy-mat-ui-ng20
51
+ ```
52
+
53
+ Install the peer dependencies if your project does not have them yet:
54
+
55
+ ```bash
56
+ ng add @angular/material
57
+ npm install @ngx-translate/core @ngx-translate/http-loader bootstrap
58
+ ```
59
+
60
+ The components use Material icons. `ng add @angular/material` normally takes care of it; otherwise add the
61
+ font to your `index.html`:
62
+
63
+ ```html
64
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
65
+ ```
66
+
67
+ ### Bundle size budget
68
+
69
+ A new Angular project fails `ng build` in production with *"bundle initial exceeded maximum budget"* once Angular Material
70
+ and this library are added: two components embed the Bootstrap stylesheet (a slimmer stylesheet is planned for 20.1). Raise the
71
+ initial budget in `angular.json` (measured: about 1.9 MB raw, 254 kB transferred, for the quick start below):
72
+
73
+ ```json
74
+ "budgets": [
75
+ { "type": "initial", "maximumWarning": "2.5MB", "maximumError": "4MB" }
76
+ ]
77
+ ```
78
+
79
+ ## Quick start
80
+
81
+ Provide ngx-translate once in your application config:
82
+
83
+ ```typescript
84
+ import { ApplicationConfig } from '@angular/core';
85
+ import { provideTranslateService } from '@ngx-translate/core';
86
+
87
+ export const appConfig: ApplicationConfig = {
88
+ providers: [provideTranslateService({ defaultLanguage: 'en' })]
89
+ };
90
+ ```
91
+
92
+ Use the table in a standalone component:
93
+
94
+ ```typescript
95
+ import { Component } from '@angular/core';
96
+ import { EasyTableComponent, EasyTableConfig, MatColumnTyped } from 'easy-mat-ui-ng20';
97
+
98
+ @Component({
99
+ selector: 'app-users',
100
+ standalone: true,
101
+ imports: [EasyTableComponent],
102
+ template: `<lib-easy-table [config]="config"></lib-easy-table>`
103
+ })
104
+ export class UsersComponent {
105
+ config: Partial<EasyTableConfig> = {
106
+ data: [
107
+ { id: 1, name: 'Alice' },
108
+ { id: 2, name: 'Bob' }
109
+ ],
110
+ displayedColumns: [
111
+ new MatColumnTyped({ name: 'id' }),
112
+ new MatColumnTyped({ name: 'name' })
113
+ ],
114
+ canCreate: true,
115
+ canUpdate: true,
116
+ canDelete: true
117
+ };
118
+ }
119
+ ```
120
+
121
+ Table events are exposed as outputs: `addItem`, `editItem`, `viewItem`, `deleteItem`, `customAction`,
122
+ `clickField`, and more (see `EasyTableComponent`).
123
+
124
+ ## Dialog example
125
+
126
+ ```typescript
127
+ import { inject } from '@angular/core';
128
+ import { CRUD, EasyDialogService, MatColumnTyped } from 'easy-mat-ui-ng20';
129
+
130
+ const dialog = inject(EasyDialogService);
131
+
132
+ dialog.open({
133
+ title: 'Edit user',
134
+ pk: 'id',
135
+ action: CRUD.UPDATE,
136
+ data: { id: 1, name: 'Alice' },
137
+ fields: [
138
+ new MatColumnTyped({ name: 'id', order: 1 }),
139
+ new MatColumnTyped({ name: 'name', order: 2, isRequired: true })
140
+ ]
141
+ }).afterClosed().subscribe(result => console.log(result?.event, result?.data));
142
+ ```
143
+
144
+ ## Generate a page
145
+
146
+ `easy-mat-ui add-page` writes an Angular page for you. You pick the components (page header, key figures, category
147
+ buttons, segmented control, language picker, card grid, and a data table with an optional child table), and it
148
+ generates the component, the template, the table configuration and the models.
149
+
150
+ ```bash
151
+ npx easy-mat-ui add-page # asks what it needs
152
+ npx easy-mat-ui add-page --name stock-items --blocks page-header,stat,table --dry-run --print
153
+ ```
154
+
155
+ - **Models**: an existing `*.model.ts` that matches the page name is reused. Otherwise a generic model (`item1`,
156
+ `item2`, `item3`) is generated, with example rows and text, icon and action columns.
157
+ - **Translations**: with ngx-translate the code uses translation keys, and the new entries are added to your English
158
+ file. Without it the texts are written in the code. Nothing is ever installed.
159
+ - **Prefer a screen?** The *Page builder* of the [live demo](__SITE_URL__/) does the same with a preview, and downloads
160
+ a description that `--config` reads. `--help` lists every option.
161
+
162
+ ## Demo application
163
+
164
+ The repository contains a runnable demo in [`projects/demo`](projects/demo). It needs no backend: a mock service
165
+ (`GeoService`) returns Observables like a real `HttpClient` service would, so replacing it is the only change a real
166
+ application needs.
167
+
168
+ ```bash
169
+ git clone https://github.com/chaibiredouane/easy-mat-ui.git
170
+ cd easy-mat-ui
171
+ npm ci
172
+ npm start # http://localhost:4200
173
+ ```
174
+
175
+ It shows what the library is for: **almost nothing to code**. Every page is four small files, in the same layout:
176
+
177
+ | File | Role |
178
+ |---|---|
179
+ | `<page>.config.ts` | The whole configuration: columns, dialog fields, table options, tabs |
180
+ | `<page>.html` | A few lines: `<lib-easy-table [config]="..." [childConfig]="...">` and its events |
181
+ | `<page>.ts` | Loads data from the service and saves the dialog results |
182
+ | `<page>.scss` | Page styles |
183
+
184
+ Three pages, built on every country of the world (Algeria first) and their cities:
185
+
186
+ 1. **Countries and their cities**: expandable rows; the child table is loaded when a row opens.
187
+ 2. **Child tables in tabs**: `childConfig` as an array, one tab per configuration.
188
+ 3. **Cities of any country**: one full table with header filters, flags, status icons and a complete
189
+ add / edit / view / delete dialog.
190
+
191
+ Each page has a *Show the code of this page* panel with its real source files, and the header has a
192
+ Light / Dark / System theme switcher.
193
+
194
+ Key points of the configuration:
195
+
196
+ - `childConfig` takes one configuration, or an array to get tabs (`tabTitle`, `tabIcon`).
197
+ - `isExpanded: true` on the parent adds the expand button; `extendRow` tells you which row opened.
198
+ - `sortedBy: ''` keeps the order given by your service (the default sorts by text).
199
+ - Rebuild a table configuration (a new `EasyTableConfig`) whenever its data changes.
200
+
201
+ The demo data lives under `projects/demo/src/app/data` and is **not** part of the npm package. Countries and cities
202
+ come from [GeoNames](https://www.geonames.org/) (CC BY 4.0), the administrative divisions of Algeria from Wikipedia
203
+ (CC BY-SA 4.0): see `DATA-LICENSE.md` and `WORLD-DATA-SOURCES.md` in that folder. Populations are source values of varying
204
+ years, not a census.
205
+
206
+ ## Themes
207
+
208
+ Light and dark themes are driven by CSS variables (`--text-color`, `--card-bg`, `--border-color`,
209
+ `--color-primary-blue`, `--radius-md`, `--shadow-md`, ...), so an application can override them without touching the
210
+ library. `EasyThemeService` switches theme at runtime, without reloading the page:
211
+
212
+ ```typescript
213
+ import { inject } from '@angular/core';
214
+ import { EasyThemeService } from 'easy-mat-ui-ng20';
215
+
216
+ const theme = inject(EasyThemeService);
217
+ theme.setTheme('dark'); // 'light' | 'dark' | 'system' (follows the operating system, live)
218
+ theme.toggle();
219
+ theme.theme(); // the applied theme, as a signal
220
+ ```
221
+
222
+ The service does nothing until you call it, never stores anything unless you give it a `storageKey`
223
+ (`EASY_THEME_OPTIONS`), and only adds the `dark-theme` class to `<body>` (the class the library stylesheet already
224
+ used) and a `data-easy-theme` attribute on `<html>`. Applications that toggle `dark-theme` themselves keep working.
225
+ Material components follow when your Angular Material theme uses `color-scheme` (for example `mat.theme`).
226
+
227
+ ## Responsive and accessibility
228
+
229
+ Below 768 px, tables size their columns to their content and scroll horizontally, and the sticky actions column shrinks
230
+ to its buttons so the data stays visible. The demo is checked at 320, 375, 430, 768, 1024, 1440 and 1920 px in both
231
+ themes (no horizontal overflow, no console error) and with axe-core (no WCAG 2 A/AA violation on the demo pages).
232
+
233
+ ## Styles
234
+
235
+ Components embed their own styles. To also get the shared classes (`green`, `red`, `taupe`, `bg-*`,
236
+ spacing and Material overrides), add the stylesheet to the `styles` array of your `angular.json`:
237
+
238
+ ```json
239
+ "styles": [
240
+ "node_modules/easy-mat-ui-ng20/styles/styles.scss",
241
+ "node_modules/flag-icons/css/flag-icons.min.css"
242
+ ]
243
+ ```
244
+
245
+ `flag-icons` is only needed for flag columns (`ColumnType.IMAGE` with a country code such as `fr`); its stylesheet is not bundled with the components.
246
+
247
+ > **Troubleshooting:** with the Angular `application` builder, the `flag-icons` stylesheet can fail in
248
+ > development with `Two output files share the same path but have different contents: media/xx.svg`.
249
+ > Set `"outputHashing": "media"` in the `development` configuration of the `build` target of your
250
+ > `angular.json`.
251
+
252
+ ## Versioning
253
+
254
+ The first number of the library version is the supported Angular major version (`20.x.x` supports
255
+ Angular 20). The remaining numbers follow [Semantic Versioning](https://semver.org/):
256
+ PATCH for bug fixes, MINOR for backward-compatible features, MAJOR for breaking changes within the
257
+ same Angular line. See [CHANGELOG.md](CHANGELOG.md).
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ npm ci
263
+ npm start # runs the demo application
264
+ npm run build # builds the library into dist/easy-mat-ui
265
+ npm test # runs the unit tests (headless Chrome)
266
+ ```
267
+
268
+ ## Contributing
269
+
270
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and the
271
+ [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities as described in [SECURITY.md](SECURITY.md).
272
+
273
+ ## License
274
+
275
+ [MIT](LICENSE)