@m1z23r/ngx-ui 0.0.1
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 +446 -0
- package/fesm2022/m1z23r-ngx-ui.mjs +584 -0
- package/fesm2022/m1z23r-ngx-ui.mjs.map +1 -0
- package/package.json +53 -0
- package/src/lib/styles/_variables.scss +77 -0
- package/src/styles.scss +52 -0
- package/types/m1z23r-ngx-ui.d.ts +124 -0
package/README.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# @m1z23r/ngx-ui
|
|
2
|
+
|
|
3
|
+
A modern, themeable Angular UI component library built with standalone components and signals. Designed for Angular 21+.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Standalone components (no NgModule required)
|
|
8
|
+
- Signal-based reactive state management
|
|
9
|
+
- CSS custom properties for easy theming
|
|
10
|
+
- Responsive layout system with mobile support
|
|
11
|
+
- OnPush change detection for optimal performance
|
|
12
|
+
- Accessible by default (ARIA attributes, focus management)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @m1z23r/ngx-ui
|
|
18
|
+
# or
|
|
19
|
+
yarn add @m1z23r/ngx-ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Setup
|
|
23
|
+
|
|
24
|
+
Import the base styles in your global stylesheet:
|
|
25
|
+
|
|
26
|
+
```scss
|
|
27
|
+
@use '@m1z23r/ngx-ui/styles';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or import specific style files:
|
|
31
|
+
|
|
32
|
+
```scss
|
|
33
|
+
@use '@m1z23r/ngx-ui/lib/styles/variables';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Components
|
|
37
|
+
|
|
38
|
+
### Button
|
|
39
|
+
|
|
40
|
+
A configurable button component with multiple variants and sizes.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { ButtonComponent } from '@m1z23r/ngx-ui';
|
|
44
|
+
|
|
45
|
+
@Component({
|
|
46
|
+
imports: [ButtonComponent],
|
|
47
|
+
template: `
|
|
48
|
+
<ui-button variant="primary" size="md" (clicked)="handleClick($event)">
|
|
49
|
+
Click me
|
|
50
|
+
</ui-button>
|
|
51
|
+
|
|
52
|
+
<ui-button variant="outline" [loading]="isLoading">
|
|
53
|
+
Submit
|
|
54
|
+
</ui-button>
|
|
55
|
+
`
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Inputs
|
|
60
|
+
|
|
61
|
+
| Input | Type | Default | Description |
|
|
62
|
+
|-------|------|---------|-------------|
|
|
63
|
+
| `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Button style variant |
|
|
64
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
65
|
+
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type |
|
|
66
|
+
| `disabled` | `boolean` | `false` | Disable the button |
|
|
67
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
68
|
+
|
|
69
|
+
#### Outputs
|
|
70
|
+
|
|
71
|
+
| Output | Type | Description |
|
|
72
|
+
|--------|------|-------------|
|
|
73
|
+
| `clicked` | `MouseEvent` | Emitted when button is clicked |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### Input
|
|
78
|
+
|
|
79
|
+
A form input component with label, hint, and error support.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { InputComponent } from '@m1z23r/ngx-ui';
|
|
83
|
+
|
|
84
|
+
@Component({
|
|
85
|
+
imports: [InputComponent],
|
|
86
|
+
template: `
|
|
87
|
+
<ui-input
|
|
88
|
+
label="Email"
|
|
89
|
+
type="email"
|
|
90
|
+
placeholder="Enter your email"
|
|
91
|
+
[(value)]="email"
|
|
92
|
+
[error]="emailError"
|
|
93
|
+
hint="We'll never share your email"
|
|
94
|
+
/>
|
|
95
|
+
`
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Inputs
|
|
100
|
+
|
|
101
|
+
| Input | Type | Default | Description |
|
|
102
|
+
|-------|------|---------|-------------|
|
|
103
|
+
| `type` | `'text' \| 'password' \| 'email' \| 'number' \| 'tel' \| 'url'` | `'text'` | Input type |
|
|
104
|
+
| `label` | `string` | `''` | Label text |
|
|
105
|
+
| `placeholder` | `string` | `''` | Placeholder text |
|
|
106
|
+
| `hint` | `string` | `''` | Hint text below input |
|
|
107
|
+
| `error` | `string` | `''` | Error message (shows error state) |
|
|
108
|
+
| `disabled` | `boolean` | `false` | Disable the input |
|
|
109
|
+
| `readonly` | `boolean` | `false` | Make input read-only |
|
|
110
|
+
| `required` | `boolean` | `false` | Mark as required (shows asterisk) |
|
|
111
|
+
| `id` | `string` | auto-generated | Custom input ID |
|
|
112
|
+
|
|
113
|
+
#### Two-way Binding
|
|
114
|
+
|
|
115
|
+
| Model | Type | Description |
|
|
116
|
+
|-------|------|-------------|
|
|
117
|
+
| `value` | `string \| number` | The input value |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Table
|
|
122
|
+
|
|
123
|
+
A data table component with sorting and custom cell templates.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { TableComponent, CellTemplateDirective, TableColumn } from '@m1z23r/ngx-ui';
|
|
127
|
+
|
|
128
|
+
interface User {
|
|
129
|
+
id: number;
|
|
130
|
+
name: string;
|
|
131
|
+
email: string;
|
|
132
|
+
status: 'active' | 'inactive';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@Component({
|
|
136
|
+
imports: [TableComponent, CellTemplateDirective],
|
|
137
|
+
template: `
|
|
138
|
+
<ui-table [data]="users" [columns]="columns" [trackByFn]="trackById">
|
|
139
|
+
<!-- Custom cell template -->
|
|
140
|
+
<ng-template uiCellTemplate="status" let-value="value">
|
|
141
|
+
<span [class]="value === 'active' ? 'text-green' : 'text-red'">
|
|
142
|
+
{{ value }}
|
|
143
|
+
</span>
|
|
144
|
+
</ng-template>
|
|
145
|
+
|
|
146
|
+
<!-- Empty state -->
|
|
147
|
+
<div slot="empty">No users found</div>
|
|
148
|
+
</ui-table>
|
|
149
|
+
`
|
|
150
|
+
})
|
|
151
|
+
export class MyComponent {
|
|
152
|
+
users: User[] = [...];
|
|
153
|
+
|
|
154
|
+
columns: TableColumn<User>[] = [
|
|
155
|
+
{ key: 'id', header: 'ID', width: '80px' },
|
|
156
|
+
{ key: 'name', header: 'Name', sortable: true },
|
|
157
|
+
{ key: 'email', header: 'Email', sortable: true },
|
|
158
|
+
{ key: 'status', header: 'Status' }
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
trackById = (user: User) => user.id;
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### Inputs
|
|
166
|
+
|
|
167
|
+
| Input | Type | Default | Description |
|
|
168
|
+
|-------|------|---------|-------------|
|
|
169
|
+
| `data` | `T[]` | `[]` | Array of data items |
|
|
170
|
+
| `columns` | `TableColumn<T>[]` | `[]` | Column definitions |
|
|
171
|
+
| `trackByFn` | `(item: T) => unknown` | `item => item` | Track by function |
|
|
172
|
+
|
|
173
|
+
#### TableColumn Interface
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface TableColumn<T> {
|
|
177
|
+
key: keyof T | string; // Property key or dot-notation path
|
|
178
|
+
header: string; // Column header text
|
|
179
|
+
sortable?: boolean; // Enable sorting
|
|
180
|
+
width?: string; // Column width (CSS value)
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Custom Cell Templates
|
|
185
|
+
|
|
186
|
+
Use `uiCellTemplate` directive to customize cell rendering:
|
|
187
|
+
|
|
188
|
+
```html
|
|
189
|
+
<ng-template uiCellTemplate="columnKey" let-row let-value="value" let-index="index">
|
|
190
|
+
<!-- Template content -->
|
|
191
|
+
</ng-template>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Template context:
|
|
195
|
+
- `$implicit` / `row` - The row data object
|
|
196
|
+
- `value` - The cell value
|
|
197
|
+
- `index` - Row index
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Layout Components
|
|
202
|
+
|
|
203
|
+
A complete layout system for building application shells with responsive sidebar.
|
|
204
|
+
|
|
205
|
+
### Quick Start
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import {
|
|
209
|
+
ShellComponent,
|
|
210
|
+
NavbarComponent,
|
|
211
|
+
SidebarComponent,
|
|
212
|
+
ContentComponent,
|
|
213
|
+
FooterComponent,
|
|
214
|
+
SidebarToggleComponent,
|
|
215
|
+
SidebarService
|
|
216
|
+
} from '@m1z23r/ngx-ui';
|
|
217
|
+
|
|
218
|
+
@Component({
|
|
219
|
+
imports: [
|
|
220
|
+
ShellComponent,
|
|
221
|
+
NavbarComponent,
|
|
222
|
+
SidebarComponent,
|
|
223
|
+
ContentComponent,
|
|
224
|
+
FooterComponent,
|
|
225
|
+
SidebarToggleComponent
|
|
226
|
+
],
|
|
227
|
+
template: `
|
|
228
|
+
<ui-shell>
|
|
229
|
+
<ui-sidebar>
|
|
230
|
+
<div slot="header">
|
|
231
|
+
<img src="logo.svg" alt="Logo" />
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<!-- Navigation items -->
|
|
235
|
+
<a href="/dashboard">Dashboard</a>
|
|
236
|
+
<a href="/settings">Settings</a>
|
|
237
|
+
|
|
238
|
+
<div slot="footer">
|
|
239
|
+
<button (click)="logout()">Logout</button>
|
|
240
|
+
</div>
|
|
241
|
+
</ui-sidebar>
|
|
242
|
+
|
|
243
|
+
<ui-navbar>
|
|
244
|
+
<div slot="start">
|
|
245
|
+
<ui-sidebar-toggle />
|
|
246
|
+
</div>
|
|
247
|
+
<div slot="center">
|
|
248
|
+
<h1>Page Title</h1>
|
|
249
|
+
</div>
|
|
250
|
+
<div slot="end">
|
|
251
|
+
<button>Profile</button>
|
|
252
|
+
</div>
|
|
253
|
+
</ui-navbar>
|
|
254
|
+
|
|
255
|
+
<ui-content>
|
|
256
|
+
<!-- Main content -->
|
|
257
|
+
<router-outlet />
|
|
258
|
+
</ui-content>
|
|
259
|
+
|
|
260
|
+
<ui-footer>
|
|
261
|
+
© 2024 My App
|
|
262
|
+
</ui-footer>
|
|
263
|
+
</ui-shell>
|
|
264
|
+
`
|
|
265
|
+
})
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Shell Component
|
|
269
|
+
|
|
270
|
+
Container component that manages the grid layout.
|
|
271
|
+
|
|
272
|
+
```html
|
|
273
|
+
<ui-shell>
|
|
274
|
+
<!-- ui-sidebar, ui-navbar, ui-content, ui-footer -->
|
|
275
|
+
</ui-shell>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Sidebar Component
|
|
279
|
+
|
|
280
|
+
Collapsible sidebar with header, navigation, and footer slots.
|
|
281
|
+
|
|
282
|
+
```html
|
|
283
|
+
<ui-sidebar>
|
|
284
|
+
<div slot="header">Logo/Brand</div>
|
|
285
|
+
<!-- Default slot: navigation items -->
|
|
286
|
+
<div slot="footer">Footer content</div>
|
|
287
|
+
</ui-sidebar>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Navbar Component
|
|
291
|
+
|
|
292
|
+
Top navigation bar with start, center, and end slots.
|
|
293
|
+
|
|
294
|
+
```html
|
|
295
|
+
<ui-navbar>
|
|
296
|
+
<div slot="start">Left content</div>
|
|
297
|
+
<div slot="center">Center content</div>
|
|
298
|
+
<div slot="end">Right content</div>
|
|
299
|
+
</ui-navbar>
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Sidebar Toggle Component
|
|
303
|
+
|
|
304
|
+
Button to toggle sidebar collapse/expand state.
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<ui-sidebar-toggle [mobileOnly]="true" />
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
| Input | Type | Default | Description |
|
|
311
|
+
|-------|------|---------|-------------|
|
|
312
|
+
| `mobileOnly` | `boolean` | `true` | Only show on mobile devices |
|
|
313
|
+
|
|
314
|
+
### SidebarService
|
|
315
|
+
|
|
316
|
+
Injectable service to programmatically control the sidebar.
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
import { SidebarService } from '@m1z23r/ngx-ui';
|
|
320
|
+
|
|
321
|
+
@Component({...})
|
|
322
|
+
export class MyComponent {
|
|
323
|
+
private sidebarService = inject(SidebarService);
|
|
324
|
+
|
|
325
|
+
// Signals
|
|
326
|
+
isCollapsed = this.sidebarService.collapsed;
|
|
327
|
+
isMobileOpen = this.sidebarService.mobileOpen;
|
|
328
|
+
isMobile = this.sidebarService.isMobile;
|
|
329
|
+
|
|
330
|
+
// Methods
|
|
331
|
+
toggle() { this.sidebarService.toggle(); }
|
|
332
|
+
expand() { this.sidebarService.expand(); }
|
|
333
|
+
collapse() { this.sidebarService.collapse(); }
|
|
334
|
+
openMobile() { this.sidebarService.openMobile(); }
|
|
335
|
+
closeMobile() { this.sidebarService.closeMobile(); }
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Theming
|
|
342
|
+
|
|
343
|
+
All components use CSS custom properties for styling. Override these in your global stylesheet:
|
|
344
|
+
|
|
345
|
+
```scss
|
|
346
|
+
:root {
|
|
347
|
+
// Primary colors
|
|
348
|
+
--ui-primary: #3b82f6;
|
|
349
|
+
--ui-primary-hover: #2563eb;
|
|
350
|
+
--ui-primary-active: #1d4ed8;
|
|
351
|
+
--ui-primary-text: #ffffff;
|
|
352
|
+
|
|
353
|
+
// Secondary colors
|
|
354
|
+
--ui-secondary: #64748b;
|
|
355
|
+
--ui-secondary-hover: #475569;
|
|
356
|
+
--ui-secondary-active: #334155;
|
|
357
|
+
--ui-secondary-text: #ffffff;
|
|
358
|
+
|
|
359
|
+
// Semantic colors
|
|
360
|
+
--ui-success: #22c55e;
|
|
361
|
+
--ui-danger: #ef4444;
|
|
362
|
+
--ui-warning: #f59e0b;
|
|
363
|
+
|
|
364
|
+
// Background colors
|
|
365
|
+
--ui-bg: #ffffff;
|
|
366
|
+
--ui-bg-secondary: #f8fafc;
|
|
367
|
+
--ui-bg-tertiary: #f1f5f9;
|
|
368
|
+
--ui-bg-hover: rgba(0, 0, 0, 0.05);
|
|
369
|
+
|
|
370
|
+
// Text colors
|
|
371
|
+
--ui-text: #1e293b;
|
|
372
|
+
--ui-text-muted: #64748b;
|
|
373
|
+
--ui-text-disabled: #94a3b8;
|
|
374
|
+
|
|
375
|
+
// Border colors
|
|
376
|
+
--ui-border: #e2e8f0;
|
|
377
|
+
--ui-border-hover: #cbd5e1;
|
|
378
|
+
--ui-border-focus: var(--ui-primary);
|
|
379
|
+
|
|
380
|
+
// Border radius
|
|
381
|
+
--ui-radius-sm: 0.25rem;
|
|
382
|
+
--ui-radius-md: 0.375rem;
|
|
383
|
+
--ui-radius-lg: 0.5rem;
|
|
384
|
+
|
|
385
|
+
// Spacing
|
|
386
|
+
--ui-spacing-xs: 0.25rem;
|
|
387
|
+
--ui-spacing-sm: 0.5rem;
|
|
388
|
+
--ui-spacing-md: 1rem;
|
|
389
|
+
--ui-spacing-lg: 1.5rem;
|
|
390
|
+
--ui-spacing-xl: 2rem;
|
|
391
|
+
|
|
392
|
+
// Layout dimensions
|
|
393
|
+
--ui-sidebar-width: 16rem;
|
|
394
|
+
--ui-sidebar-collapsed-width: 4rem;
|
|
395
|
+
--ui-navbar-height: 4rem;
|
|
396
|
+
--ui-footer-height: 3rem;
|
|
397
|
+
|
|
398
|
+
// Shadows
|
|
399
|
+
--ui-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
400
|
+
--ui-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
|
401
|
+
--ui-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
|
402
|
+
|
|
403
|
+
// Transitions
|
|
404
|
+
--ui-transition-fast: 150ms ease;
|
|
405
|
+
--ui-transition-normal: 200ms ease;
|
|
406
|
+
--ui-transition-slow: 300ms ease;
|
|
407
|
+
|
|
408
|
+
// Font sizes
|
|
409
|
+
--ui-font-xs: 0.75rem;
|
|
410
|
+
--ui-font-sm: 0.875rem;
|
|
411
|
+
--ui-font-md: 1rem;
|
|
412
|
+
--ui-font-lg: 1.125rem;
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Dark Theme Example
|
|
417
|
+
|
|
418
|
+
```scss
|
|
419
|
+
[data-theme="dark"] {
|
|
420
|
+
--ui-bg: #0f172a;
|
|
421
|
+
--ui-bg-secondary: #1e293b;
|
|
422
|
+
--ui-bg-tertiary: #334155;
|
|
423
|
+
--ui-text: #f1f5f9;
|
|
424
|
+
--ui-text-muted: #94a3b8;
|
|
425
|
+
--ui-border: #334155;
|
|
426
|
+
--ui-border-hover: #475569;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Browser Support
|
|
433
|
+
|
|
434
|
+
- Chrome (latest)
|
|
435
|
+
- Firefox (latest)
|
|
436
|
+
- Safari (latest)
|
|
437
|
+
- Edge (latest)
|
|
438
|
+
|
|
439
|
+
## Requirements
|
|
440
|
+
|
|
441
|
+
- Angular 21.0.0 or higher
|
|
442
|
+
- TypeScript 5.9 or higher
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT
|