@saitec/ui 0.1.0 → 0.1.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 +510 -64
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,64 +1,510 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
##
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
# @saitec/ui
|
|
2
|
+
|
|
3
|
+
Reusable Angular UI component library developed by **SAITEC Ingeniería S.A.S.**
|
|
4
|
+
|
|
5
|
+
`@saitec/ui` provides standalone Angular components, shared design tokens, light/dark themes, and reusable interaction patterns for SAITEC applications.
|
|
6
|
+
|
|
7
|
+
The library is designed so consuming applications depend on the public `@saitec/ui/*` API instead of third-party component suites or internal source paths.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Standalone Angular components
|
|
12
|
+
- Angular Forms and `ControlValueAccessor` support
|
|
13
|
+
- Signal-based APIs
|
|
14
|
+
- Light and dark themes
|
|
15
|
+
- CSS custom-property design tokens
|
|
16
|
+
- Global, component, and instance-level customization
|
|
17
|
+
- Angular CDK for overlay-based components where appropriate
|
|
18
|
+
- No Tailwind dependency inside SUI
|
|
19
|
+
- Secondary entry points such as `@saitec/ui/button` and `@saitec/ui/table`
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @saitec/ui
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Some components use Angular CDK. If needed:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @angular/cdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Angular framework packages are provided by the consuming application.
|
|
34
|
+
|
|
35
|
+
## Global styles
|
|
36
|
+
|
|
37
|
+
Import SUI once from the application's global stylesheet:
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
@import "@saitec/ui/styles.css";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If the application uses Tailwind:
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
@import "tailwindcss";
|
|
47
|
+
@import "@saitec/ui/styles.css";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
SUI itself does not require Tailwind.
|
|
51
|
+
|
|
52
|
+
## Basic usage
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { Component } from '@angular/core';
|
|
56
|
+
import { SuiButton } from '@saitec/ui/button';
|
|
57
|
+
import { SuiTag } from '@saitec/ui/tag';
|
|
58
|
+
|
|
59
|
+
@Component({
|
|
60
|
+
selector: 'app-example',
|
|
61
|
+
standalone: true,
|
|
62
|
+
imports: [
|
|
63
|
+
SuiButton,
|
|
64
|
+
SuiTag
|
|
65
|
+
],
|
|
66
|
+
template: `
|
|
67
|
+
<sui-button>
|
|
68
|
+
Save
|
|
69
|
+
</sui-button>
|
|
70
|
+
|
|
71
|
+
<sui-tag severity="success">
|
|
72
|
+
Active
|
|
73
|
+
</sui-tag>
|
|
74
|
+
`
|
|
75
|
+
})
|
|
76
|
+
export class ExampleComponent {
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Secondary entry points
|
|
81
|
+
|
|
82
|
+
Import components through their public package entry points:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { SuiButton } from '@saitec/ui/button';
|
|
86
|
+
import { SuiInput } from '@saitec/ui/input';
|
|
87
|
+
import { SuiDialog } from '@saitec/ui/dialog';
|
|
88
|
+
import { SuiTable, SuiColumn, SuiCell } from '@saitec/ui/table';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Shared types are exposed from:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { SuiOption } from '@saitec/ui/core';
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Do not import internal source files.
|
|
98
|
+
|
|
99
|
+
Bad:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { SuiButton } from '@saitec/ui/button/src/button.component';
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Good:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { SuiButton } from '@saitec/ui/button';
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Themes
|
|
112
|
+
|
|
113
|
+
SUI uses the `data-theme` attribute.
|
|
114
|
+
|
|
115
|
+
Light:
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<html data-theme="light">
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Dark:
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<html data-theme="dark">
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Runtime switch:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
document.documentElement.setAttribute(
|
|
131
|
+
'data-theme',
|
|
132
|
+
'dark'
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
SUI components consume semantic variables such as:
|
|
137
|
+
|
|
138
|
+
```css
|
|
139
|
+
--sui-color-background
|
|
140
|
+
--sui-color-surface
|
|
141
|
+
--sui-color-content
|
|
142
|
+
--sui-color-border
|
|
143
|
+
--sui-color-primary
|
|
144
|
+
--sui-color-danger
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Changing the theme updates those semantic values globally.
|
|
148
|
+
|
|
149
|
+
## Design tokens
|
|
150
|
+
|
|
151
|
+
The design-token system is organized into layers:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
Primitive tokens
|
|
155
|
+
↓
|
|
156
|
+
Theme semantic tokens
|
|
157
|
+
↓
|
|
158
|
+
Foundation tokens
|
|
159
|
+
↓
|
|
160
|
+
Component tokens
|
|
161
|
+
↓
|
|
162
|
+
Component CSS
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Main files:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
src/lib/core/tokens/
|
|
169
|
+
├── primitives.css
|
|
170
|
+
├── foundations.css
|
|
171
|
+
├── components.css
|
|
172
|
+
└── components/
|
|
173
|
+
├── button.css
|
|
174
|
+
├── input.css
|
|
175
|
+
├── table.css
|
|
176
|
+
└── ...
|
|
177
|
+
|
|
178
|
+
src/lib/core/themes/
|
|
179
|
+
├── light.css
|
|
180
|
+
└── dark.css
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Primitive tokens
|
|
184
|
+
|
|
185
|
+
Raw design values:
|
|
186
|
+
|
|
187
|
+
```css
|
|
188
|
+
--sui-palette-brand-600
|
|
189
|
+
--sui-palette-neutral-900
|
|
190
|
+
--sui-radius-md
|
|
191
|
+
--sui-shadow-sm
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Semantic theme tokens
|
|
195
|
+
|
|
196
|
+
Theme-level meaning:
|
|
197
|
+
|
|
198
|
+
```css
|
|
199
|
+
--sui-color-primary
|
|
200
|
+
--sui-color-surface
|
|
201
|
+
--sui-color-content
|
|
202
|
+
--sui-color-success
|
|
203
|
+
--sui-color-warning
|
|
204
|
+
--sui-color-danger
|
|
205
|
+
--sui-color-info
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Foundation tokens
|
|
209
|
+
|
|
210
|
+
Shared control and layout values:
|
|
211
|
+
|
|
212
|
+
```css
|
|
213
|
+
--sui-control-height-md
|
|
214
|
+
--sui-control-padding-x-md
|
|
215
|
+
--sui-space-4
|
|
216
|
+
--sui-focus-ring-width
|
|
217
|
+
--sui-duration-normal
|
|
218
|
+
--sui-z-dialog
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Component tokens
|
|
222
|
+
|
|
223
|
+
Each component exposes its own styling contract:
|
|
224
|
+
|
|
225
|
+
```css
|
|
226
|
+
--sui-button-primary-background
|
|
227
|
+
--sui-button-radius
|
|
228
|
+
--sui-table-header-background
|
|
229
|
+
--sui-dialog-background
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Customization
|
|
233
|
+
|
|
234
|
+
### Global brand customization
|
|
235
|
+
|
|
236
|
+
```css
|
|
237
|
+
:root {
|
|
238
|
+
--sui-color-primary: #0057b8;
|
|
239
|
+
--sui-color-primary-hover: #004a9d;
|
|
240
|
+
--sui-color-primary-active: #003d82;
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Component-level customization
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
:root {
|
|
248
|
+
--sui-button-radius: 9999px;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Single-instance customization
|
|
253
|
+
|
|
254
|
+
```html
|
|
255
|
+
<sui-button class="special-button">
|
|
256
|
+
Save
|
|
257
|
+
</sui-button>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```css
|
|
261
|
+
.special-button {
|
|
262
|
+
--sui-button-primary-background: #7c3aed;
|
|
263
|
+
--sui-button-primary-background-hover: #6d28d9;
|
|
264
|
+
--sui-button-radius: 0;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
This avoids `::ng-deep` and keeps consumers independent from internal component markup.
|
|
269
|
+
|
|
270
|
+
## Forms
|
|
271
|
+
|
|
272
|
+
Form controls implement Angular `ControlValueAccessor` where appropriate.
|
|
273
|
+
|
|
274
|
+
```html
|
|
275
|
+
<sui-input
|
|
276
|
+
formControlName="customerName"
|
|
277
|
+
placeholder="Customer name">
|
|
278
|
+
</sui-input>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Shared options
|
|
282
|
+
|
|
283
|
+
Selection components share a common option contract:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import { SuiOption } from '@saitec/ui/core';
|
|
287
|
+
|
|
288
|
+
const countries: SuiOption<string>[] = [
|
|
289
|
+
{
|
|
290
|
+
label: 'Colombia',
|
|
291
|
+
value: 'CO'
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
label: 'Ecuador',
|
|
295
|
+
value: 'EC'
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
label: 'Peru',
|
|
299
|
+
value: 'PE'
|
|
300
|
+
}
|
|
301
|
+
];
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The same collection can be used with components such as:
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<sui-select [options]="countries" />
|
|
308
|
+
<sui-autocomplete [options]="countries" />
|
|
309
|
+
<sui-multiselect [options]="countries" />
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Table
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import {
|
|
316
|
+
SuiCell,
|
|
317
|
+
SuiColumn,
|
|
318
|
+
SuiTable
|
|
319
|
+
} from '@saitec/ui/table';
|
|
320
|
+
|
|
321
|
+
import {
|
|
322
|
+
SuiTag
|
|
323
|
+
} from '@saitec/ui/tag';
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
```html
|
|
327
|
+
<sui-table
|
|
328
|
+
[value]="products"
|
|
329
|
+
[striped]="true"
|
|
330
|
+
[hoverable]="true">
|
|
331
|
+
|
|
332
|
+
<sui-column
|
|
333
|
+
field="code"
|
|
334
|
+
header="Product"
|
|
335
|
+
[sortable]="true">
|
|
336
|
+
</sui-column>
|
|
337
|
+
|
|
338
|
+
<sui-column
|
|
339
|
+
field="weight"
|
|
340
|
+
header="Weight"
|
|
341
|
+
align="right"
|
|
342
|
+
[sortable]="true">
|
|
343
|
+
</sui-column>
|
|
344
|
+
|
|
345
|
+
<sui-column
|
|
346
|
+
field="status"
|
|
347
|
+
header="Status">
|
|
348
|
+
|
|
349
|
+
<ng-template
|
|
350
|
+
suiCell
|
|
351
|
+
let-value="value">
|
|
352
|
+
|
|
353
|
+
<sui-tag severity="success">
|
|
354
|
+
{{ value }}
|
|
355
|
+
</sui-tag>
|
|
356
|
+
|
|
357
|
+
</ng-template>
|
|
358
|
+
|
|
359
|
+
</sui-column>
|
|
360
|
+
|
|
361
|
+
</sui-table>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
When using `suiCell`, remember to import `SuiCell`.
|
|
365
|
+
|
|
366
|
+
## Toast and confirm
|
|
367
|
+
|
|
368
|
+
Place one instance near the root of the application:
|
|
369
|
+
|
|
370
|
+
```html
|
|
371
|
+
<router-outlet />
|
|
372
|
+
|
|
373
|
+
<sui-toast />
|
|
374
|
+
<sui-confirm />
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Then inject the corresponding service:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
private readonly toast =
|
|
381
|
+
inject(SuiToastService);
|
|
382
|
+
|
|
383
|
+
private readonly confirm =
|
|
384
|
+
inject(SuiConfirmService);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## File upload
|
|
388
|
+
|
|
389
|
+
`SuiFileUpload` manages file selection and UI behavior. HTTP upload remains the responsibility of the consuming application.
|
|
390
|
+
|
|
391
|
+
```html
|
|
392
|
+
<sui-file-upload
|
|
393
|
+
[multiple]="true"
|
|
394
|
+
accept=".pdf,.png,.jpg"
|
|
395
|
+
[maxFileSize]="10 * 1024 * 1024"
|
|
396
|
+
(filesChange)="files = $event">
|
|
397
|
+
</sui-file-upload>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Available components
|
|
401
|
+
|
|
402
|
+
| Category | Components |
|
|
403
|
+
| --- | --- |
|
|
404
|
+
| Form | FormField, Input, Textarea, Checkbox, ToggleSwitch, InputNumber, DatePicker |
|
|
405
|
+
| Selection | Select, Autocomplete, MultiSelect |
|
|
406
|
+
| Actions | Button |
|
|
407
|
+
| Data | Table |
|
|
408
|
+
| Navigation | Menu, Menubar, Tabs |
|
|
409
|
+
| Status | Badge, Tag, Message, ProgressSpinner |
|
|
410
|
+
| Containers | Card, Panel, Fieldset, Toolbar, Divider |
|
|
411
|
+
| Overlay | Dialog, Drawer, Tooltip, Toast, Confirm |
|
|
412
|
+
| Files | FileUpload |
|
|
413
|
+
| Content | Chip |
|
|
414
|
+
|
|
415
|
+
## Development
|
|
416
|
+
|
|
417
|
+
Build the library in watch mode:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
ng build ui --watch --configuration development
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Run the showcase separately:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
ng serve showcase
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Production build:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
ng build ui --configuration production
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
The distributable package is generated under:
|
|
436
|
+
|
|
437
|
+
```text
|
|
438
|
+
dist/ui
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Publishing
|
|
442
|
+
|
|
443
|
+
Publish the compiled package, not `projects/ui`.
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
ng build ui --configuration production
|
|
447
|
+
|
|
448
|
+
cd dist/ui
|
|
449
|
+
|
|
450
|
+
npm publish --dry-run --access public
|
|
451
|
+
npm publish --access public
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
The version must be incremented before publishing another release.
|
|
455
|
+
|
|
456
|
+
Recommended versioning while the API is still evolving:
|
|
457
|
+
|
|
458
|
+
```text
|
|
459
|
+
0.1.x
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Then move to `1.0.0` when the public API is considered stable.
|
|
463
|
+
|
|
464
|
+
## Architecture guidelines
|
|
465
|
+
|
|
466
|
+
When adding components:
|
|
467
|
+
|
|
468
|
+
1. Expose a small application-focused API instead of cloning a third-party component API.
|
|
469
|
+
2. Prefer native HTML semantics when they already provide good accessibility and behavior.
|
|
470
|
+
3. Use Angular CDK where robust overlay, focus, or positioning infrastructure is needed.
|
|
471
|
+
4. Implement `ControlValueAccessor` for form controls.
|
|
472
|
+
5. Keep Angular components standalone.
|
|
473
|
+
6. Prefer signals for inputs, models, outputs, and internal state where appropriate.
|
|
474
|
+
7. Reuse shared contracts such as `SuiOption<T>`.
|
|
475
|
+
8. Keep visual design decisions in design tokens.
|
|
476
|
+
9. Keep component CSS focused on layout, structure, and state behavior.
|
|
477
|
+
10. Never require consuming applications to import internal source paths.
|
|
478
|
+
|
|
479
|
+
## Styling rule
|
|
480
|
+
|
|
481
|
+
A core SUI rule is:
|
|
482
|
+
|
|
483
|
+
> Component CSS describes how a component behaves and is laid out. Design tokens describe what it looks like.
|
|
484
|
+
|
|
485
|
+
Prefer:
|
|
486
|
+
|
|
487
|
+
```css
|
|
488
|
+
.sui-button--primary {
|
|
489
|
+
background-color:
|
|
490
|
+
var(--sui-button-primary-background);
|
|
491
|
+
|
|
492
|
+
color:
|
|
493
|
+
var(--sui-button-primary-text);
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
instead of:
|
|
498
|
+
|
|
499
|
+
```css
|
|
500
|
+
.sui-button--primary {
|
|
501
|
+
background-color: #2563eb;
|
|
502
|
+
color: #ffffff;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## License
|
|
507
|
+
|
|
508
|
+
Maintained by **SAITEC Ingeniería S.A.S.**
|
|
509
|
+
|
|
510
|
+
Set the package `license` field and this section according to the distribution model selected for the library.
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saitec/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "SAITEC Angular UI component library",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/saitec-ingenieria/saitec-ui.git"
|
|
8
|
+
},
|
|
5
9
|
"license": "UNLICENSED",
|
|
6
10
|
"publishConfig": {
|
|
7
11
|
"access": "public"
|