@keepui/ui 0.4.0 → 0.5.0
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 +741 -276
- package/fesm2022/keepui-ui.mjs +464 -2
- package/fesm2022/keepui-ui.mjs.map +1 -1
- package/lib/components/stepper/stepper.component.d.ts +67 -0
- package/lib/components/stepper/stepper.component.d.ts.map +1 -0
- package/lib/components/stepper/stepper.types.d.ts +16 -0
- package/lib/components/stepper/stepper.types.d.ts.map +1 -0
- package/lib/components/tab-group/tab-group.component.d.ts +52 -0
- package/lib/components/tab-group/tab-group.component.d.ts.map +1 -0
- package/lib/components/tab-group/tab-group.types.d.ts +14 -0
- package/lib/components/tab-group/tab-group.types.d.ts.map +1 -0
- package/package.json +1 -1
- package/public-api.d.ts +4 -0
- package/public-api.d.ts.map +1 -1
- package/styles/prebuilt.css +1 -1
package/README.md
CHANGED
|
@@ -1,153 +1,167 @@
|
|
|
1
1
|
# KeepUI
|
|
2
2
|
|
|
3
|
-
> Angular
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Table of Contents
|
|
11
|
-
|
|
12
|
-
- [Purpose](#purpose)
|
|
13
|
-
- [Package Structure](#package-structure)
|
|
14
|
-
- [Installation](#installation)
|
|
15
|
-
- [Setup](#setup)
|
|
16
|
-
- [1. Import styles](#1-import-styles)
|
|
17
|
-
- [2. Register providers](#2-register-providers)
|
|
18
|
-
- [Available Components](#available-components)
|
|
19
|
-
- [`<keepui-button>`](#keepui-button)
|
|
20
|
-
- [`<keepui-card>`](#keepui-card)
|
|
21
|
-
- [`<keepui-icon>`](#keepui-icon)
|
|
22
|
-
- [`<keepui-icon-action-button>`](#keepui-icon-action-button)
|
|
23
|
-
- [`<keepui-image-preview>`](#keepui-image-preview)
|
|
24
|
-
- [i18n](#i18n)
|
|
25
|
-
- [Theming](#theming)
|
|
26
|
-
- [Architecture Notes](#architecture-notes)
|
|
27
|
-
- [Testing](#testing)
|
|
28
|
-
- [Building](#building)
|
|
29
|
-
- [Publishing to npm](#publishing-to-npm)
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Purpose
|
|
34
|
-
|
|
35
|
-
KeepUI is a reusable Angular component library designed to work seamlessly across:
|
|
36
|
-
|
|
37
|
-
- **Standard Angular web applications** (browser only)
|
|
38
|
-
- **Angular + Capacitor applications** (iOS, Android, PWA)
|
|
39
|
-
|
|
40
|
-
The library uses a **Port/Adapter pattern** to keep UI components fully decoupled from platform-specific APIs. Components never import `@capacitor/*` directly; they depend on injected interface implementations registered via functional providers.
|
|
3
|
+
> Component library for Angular with multi-platform support (web and Angular + Capacitor).
|
|
4
|
+
> Built on **Tailwind CSS v4** with full **light/dark** theming and **i18n** via `@jsverse/transloco`.
|
|
5
|
+
>
|
|
6
|
+
> **Auto-generated** from JSDoc in the source files.
|
|
7
|
+
> Do **not** edit manually — run `npm run docs:generate` to update.
|
|
41
8
|
|
|
42
9
|
---
|
|
10
|
+
## 1. Package identity
|
|
43
11
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
| Package | Description |
|
|
12
|
+
| Field | Value |
|
|
47
13
|
|---|---|
|
|
48
|
-
| `@keepui/ui` |
|
|
49
|
-
|
|
|
14
|
+
| Package name | `@keepui/ui` |
|
|
15
|
+
| Angular compat | `>= 19` |
|
|
16
|
+
| Style engine | Tailwind CSS v4 |
|
|
17
|
+
| i18n engine | `@jsverse/transloco` |
|
|
50
18
|
|
|
51
19
|
---
|
|
20
|
+
## 2. Installation
|
|
52
21
|
|
|
53
|
-
|
|
22
|
+
### Option A — local build (development)
|
|
54
23
|
|
|
55
24
|
```bash
|
|
56
|
-
#
|
|
57
|
-
|
|
25
|
+
npm run build # outputs to dist/keep-ui
|
|
26
|
+
npm install /absolute/path/to/dist/keep-ui
|
|
27
|
+
```
|
|
58
28
|
|
|
59
|
-
|
|
29
|
+
### Option B — npm registry
|
|
30
|
+
|
|
31
|
+
```bash
|
|
60
32
|
npm install @keepui/ui
|
|
61
33
|
```
|
|
62
34
|
|
|
63
|
-
|
|
35
|
+
### Required peer dependencies
|
|
64
36
|
|
|
65
37
|
```bash
|
|
66
|
-
npm install @
|
|
67
|
-
npx cap sync
|
|
38
|
+
npm install @angular/common @angular/core @jsverse/transloco
|
|
68
39
|
```
|
|
69
40
|
|
|
70
41
|
---
|
|
42
|
+
## 3. Global styles (required)
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### 1. Import styles
|
|
75
|
-
|
|
76
|
-
KeepUI components use CSS custom properties for theming. Import the library styles in your global stylesheet **before** any component-level styles.
|
|
77
|
-
|
|
78
|
-
**If your project uses Tailwind CSS v4:**
|
|
44
|
+
Add once to the host application's global stylesheet (e.g. `src/styles.css`):
|
|
79
45
|
|
|
80
46
|
```css
|
|
81
|
-
/* src/styles.css */
|
|
82
|
-
@import "tailwindcss";
|
|
83
47
|
@import "@keepui/ui/styles";
|
|
84
48
|
```
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
Provides:
|
|
51
|
+
- Light theme CSS custom properties (default)
|
|
52
|
+
- Dark theme via `[data-theme="dark"]`
|
|
53
|
+
- Auto dark via `@media (prefers-color-scheme: dark)`
|
|
54
|
+
- Tailwind v4 `@theme inline` mappings for all `bg-keepui-*`, `text-keepui-*`, `border-keepui-*`, `shadow-keepui-*` utilities
|
|
87
55
|
|
|
88
|
-
|
|
89
|
-
/* src/styles.css */
|
|
90
|
-
@import "@keepui/ui/styles/prebuilt.css";
|
|
91
|
-
```
|
|
56
|
+
#### Theme switching at runtime
|
|
92
57
|
|
|
93
|
-
|
|
58
|
+
```ts
|
|
59
|
+
document.documentElement.setAttribute('data-theme', 'dark'); // force dark
|
|
60
|
+
document.documentElement.setAttribute('data-theme', 'light'); // force light
|
|
61
|
+
document.documentElement.removeAttribute('data-theme'); // follow OS
|
|
62
|
+
```
|
|
94
63
|
|
|
95
|
-
|
|
64
|
+
---
|
|
65
|
+
## 4. Provider setup (`app.config.ts`)
|
|
96
66
|
|
|
97
|
-
|
|
67
|
+
### Web application
|
|
98
68
|
|
|
99
69
|
```ts
|
|
100
|
-
// src/app/app.config.ts
|
|
101
|
-
import { ApplicationConfig } from '@angular/core';
|
|
102
|
-
import { provideRouter } from '@angular/router';
|
|
103
70
|
import { provideKeepUi, provideKeepUiI18n } from '@keepui/ui';
|
|
104
71
|
|
|
105
72
|
export const appConfig: ApplicationConfig = {
|
|
106
73
|
providers: [
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
provideKeepUiI18n({ defaultLang: '
|
|
74
|
+
provideKeepUi(), // registers WebFileService for FILE_PORT
|
|
75
|
+
provideKeepUiI18n(), // default language: 'en'
|
|
76
|
+
// provideKeepUiI18n({ defaultLang: 'es' }),
|
|
110
77
|
],
|
|
111
78
|
};
|
|
112
79
|
```
|
|
113
80
|
|
|
114
|
-
|
|
81
|
+
### Angular + Capacitor application
|
|
115
82
|
|
|
116
83
|
```ts
|
|
117
|
-
// src/app/app.config.ts
|
|
118
|
-
import { ApplicationConfig } from '@angular/core';
|
|
119
|
-
import { provideRouter } from '@angular/router';
|
|
120
|
-
import { provideKeepUiI18n } from '@keepui/ui';
|
|
121
84
|
import { provideKeepUiCapacitor } from '@keepui/ui/capacitor';
|
|
85
|
+
import { provideKeepUiI18n } from '@keepui/ui';
|
|
86
|
+
|
|
87
|
+
export const appConfig: ApplicationConfig = {
|
|
88
|
+
providers: [provideKeepUiCapacitor(), provideKeepUiI18n()],
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
> **Rule:** Never register both `provideKeepUi()` and `provideKeepUiCapacitor()` at the same time.
|
|
93
|
+
|
|
94
|
+
### Available provider functions
|
|
122
95
|
|
|
96
|
+
#### `provideKeepUiI18n(options?: KeepUiI18nOptions = {}): EnvironmentProviders`
|
|
97
|
+
|
|
98
|
+
Registers all providers required for KeepUI internationalisation.
|
|
99
|
+
|
|
100
|
+
- Configures a self-contained Transloco instance scoped to `'keepui'`.
|
|
101
|
+
- Bundles all translations **inline** — no HTTP assets required.
|
|
102
|
+
- Provides {@link KeepUiLanguageService} so the host app can switch locale.
|
|
103
|
+
|
|
104
|
+
### Usage in `app.config.ts`
|
|
105
|
+
```ts
|
|
123
106
|
export const appConfig: ApplicationConfig = {
|
|
124
107
|
providers: [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
provideKeepUiI18n({ defaultLang: '
|
|
108
|
+
provideKeepUi(),
|
|
109
|
+
provideKeepUiI18n(), // default language: 'en'
|
|
110
|
+
provideKeepUiI18n({ defaultLang: 'es' }), // or start in Spanish
|
|
128
111
|
],
|
|
129
112
|
};
|
|
130
113
|
```
|
|
131
114
|
|
|
132
|
-
|
|
115
|
+
### Changing language at runtime
|
|
116
|
+
```ts
|
|
117
|
+
const lang = inject(KeepUiLanguageService);
|
|
118
|
+
lang.setLanguage('de');
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> **Note:** If your application already calls `provideTransloco()`, do NOT
|
|
122
|
+
> call `provideKeepUiI18n()` — instead configure your Transloco loader to
|
|
123
|
+
> handle the `'keepui/{lang}'` scope paths, and provide `KeepUiLanguageService`
|
|
124
|
+
> manually.
|
|
125
|
+
|
|
126
|
+
#### `provideKeepUi(): EnvironmentProviders`
|
|
127
|
+
|
|
128
|
+
Registers KeepUI core providers for a **web** Angular application.
|
|
129
|
+
|
|
130
|
+
Registers `WebFileService` as the implementation of `FILE_PORT`, enabling
|
|
131
|
+
all KeepUI components to use the browser's native file picker.
|
|
132
|
+
|
|
133
|
+
Add to `app.config.ts`:
|
|
134
|
+
```ts
|
|
135
|
+
export const appConfig: ApplicationConfig = {
|
|
136
|
+
providers: [provideKeepUi()],
|
|
137
|
+
};
|
|
138
|
+
```
|
|
133
139
|
|
|
134
140
|
---
|
|
135
141
|
|
|
136
|
-
##
|
|
142
|
+
## 5. Component API reference
|
|
137
143
|
|
|
138
|
-
|
|
144
|
+
All components are **standalone**. Import directly from `@keepui/ui`.
|
|
139
145
|
|
|
140
|
-
|
|
146
|
+
### 5.1 `ButtonComponent`
|
|
147
|
+
|
|
148
|
+
**Selector:** `keepui-button`
|
|
149
|
+
**Import:** `import { ButtonComponent } from '@keepui/ui';`
|
|
150
|
+
|
|
151
|
+
Accessible, themed action button with support for variants, shapes, sizes,
|
|
152
|
+
loading state, full-width layout, and named icon slots.
|
|
153
|
+
|
|
154
|
+
Works identically on **web** and **Angular + Capacitor** (no native API usage).
|
|
141
155
|
|
|
142
156
|
```html
|
|
143
|
-
<!-- Basic -->
|
|
157
|
+
<!-- Basic usage -->
|
|
144
158
|
<keepui-button (clicked)="save()">Save</keepui-button>
|
|
145
159
|
|
|
146
|
-
<!--
|
|
147
|
-
<keepui-button variant="
|
|
160
|
+
<!-- Primary, pill-shaped, fixed width -->
|
|
161
|
+
<keepui-button variant="primary" shape="pill">Confirm</keepui-button>
|
|
148
162
|
|
|
149
|
-
<!-- With leading icon -->
|
|
150
|
-
<keepui-button variant="
|
|
163
|
+
<!-- With leading icon (any inline element) -->
|
|
164
|
+
<keepui-button variant="outline" size="auto">
|
|
151
165
|
<svg slot="leading" width="16" height="16" aria-hidden="true">…</svg>
|
|
152
166
|
Upload
|
|
153
167
|
</keepui-button>
|
|
@@ -155,338 +169,789 @@ Accessible, themed action button with variants, shapes, sizes, loading state, fu
|
|
|
155
169
|
<!-- Loading state -->
|
|
156
170
|
<keepui-button [loading]="isSaving()">Saving…</keepui-button>
|
|
157
171
|
|
|
158
|
-
<!-- Full-width -->
|
|
159
|
-
<keepui-button [fullWidth]="true">
|
|
172
|
+
<!-- Full-width, danger -->
|
|
173
|
+
<keepui-button variant="danger" [fullWidth]="true">Delete account</keepui-button>
|
|
160
174
|
|
|
161
|
-
<!-- Icon-only (ariaLabel
|
|
175
|
+
<!-- Icon-only (requires ariaLabel for accessibility) -->
|
|
162
176
|
<keepui-button variant="ghost" size="auto" ariaLabel="Close dialog">
|
|
163
177
|
<svg slot="leading" …>…</svg>
|
|
164
178
|
</keepui-button>
|
|
165
179
|
```
|
|
166
180
|
|
|
167
|
-
|
|
181
|
+
#### Inputs
|
|
168
182
|
|
|
169
183
|
| Input | Type | Default | Description |
|
|
170
184
|
|---|---|---|---|
|
|
171
|
-
| `variant` | `
|
|
172
|
-
| `size` | `
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
| `variant` | `ButtonVariant` | `'primary'` | Visual style of the button. |
|
|
186
|
+
| `size` | `ButtonSize` | `'md'` | Size mode.
|
|
187
|
+
- `md` → fixed 160 px wide, 40 px tall.
|
|
188
|
+
- `auto` → padding-driven width, 40 px tall. |
|
|
189
|
+
| `shape` | `ButtonShape` | `'pill'` | Border-radius style. |
|
|
190
|
+
| `type` | `ButtonType` | `'button'` | HTML `type` attribute of the inner `<button>`. |
|
|
191
|
+
| `disabled` | `boolean` | `false` | Disables the button when `true`. |
|
|
192
|
+
| `loading` | `boolean` | `false` | Replaces the content with an animated spinner and sets `aria-busy`.
|
|
193
|
+
Also disables the button until the operation completes. |
|
|
194
|
+
| `fullWidth` | `boolean` | `false` | Expands the button to fill its container width. |
|
|
195
|
+
| `ariaLabel` | `string` | `''` | Accessible label for icon-only buttons.
|
|
196
|
+
When provided, sets the `aria-label` attribute on the inner `<button>`. |
|
|
197
|
+
|
|
198
|
+
#### Outputs
|
|
199
|
+
|
|
200
|
+
| Output | Emitter type | Description |
|
|
183
201
|
|---|---|---|
|
|
184
|
-
| `clicked` | `void
|
|
202
|
+
| `clicked` | `OutputEmitterRef<void>` | Emitted when the button is clicked and is not disabled or loading. |
|
|
185
203
|
|
|
186
|
-
|
|
204
|
+
#### Content slots (`ng-content`)
|
|
187
205
|
|
|
188
206
|
| Slot | Description |
|
|
189
207
|
|---|---|
|
|
190
|
-
|
|
|
191
|
-
| `slot=
|
|
192
|
-
|
|
|
208
|
+
| *(default)* | Main projected content |
|
|
209
|
+
| `[slot='leading']` | Leading icon/element. Hidden while `loading`. |
|
|
210
|
+
| `[slot='trailing']` | Trailing icon/element. Hidden while `loading`. |
|
|
193
211
|
|
|
194
212
|
---
|
|
213
|
+
### 5.2 `CardComponent`
|
|
195
214
|
|
|
196
|
-
|
|
215
|
+
**Selector:** `keepui-card`
|
|
216
|
+
**Import:** `import { CardComponent } from '@keepui/ui';`
|
|
197
217
|
|
|
198
|
-
|
|
218
|
+
Contenedor versátil con soporte de variante, padding, color, estado clickable,
|
|
219
|
+
seleccionado y scrollable.
|
|
199
220
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
221
|
+
`padding="screen"` aplica padding lateral y superior pero omite el inferior
|
|
222
|
+
intencionadamente para que el contenido parezca continuar más allá del área visible,
|
|
223
|
+
invitando al usuario a hacer scroll. Un `div` espaciador se inserta automáticamente
|
|
224
|
+
al final del contenido proyectado: cuando el usuario llega al fondo, el espaciador
|
|
225
|
+
reproduce el padding inferior correcto sin que el consumidor deba declararlo.
|
|
203
226
|
|
|
204
|
-
|
|
205
|
-
<keepui-card
|
|
227
|
+
```html
|
|
228
|
+
<keepui-card>Contenido</keepui-card>
|
|
206
229
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Option A
|
|
230
|
+
<keepui-card variant="flat" padding="lg" [clickable]="true" (clicked)="onSelect()">
|
|
231
|
+
Card clicable
|
|
210
232
|
</keepui-card>
|
|
211
233
|
|
|
212
|
-
<!-- Full-height scrollable panel -->
|
|
213
234
|
<div class="h-screen overflow-hidden">
|
|
214
235
|
<keepui-card padding="screen" [scrollable]="true" [fullHeight]="true">
|
|
215
|
-
|
|
236
|
+
Contenido largo — el padding inferior se gestiona automáticamente
|
|
216
237
|
</keepui-card>
|
|
217
238
|
</div>
|
|
218
239
|
```
|
|
219
240
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
**Inputs:**
|
|
241
|
+
#### Inputs
|
|
223
242
|
|
|
224
243
|
| Input | Type | Default | Description |
|
|
225
244
|
|---|---|---|---|
|
|
226
|
-
| `variant` | `
|
|
227
|
-
| `padding` | `
|
|
228
|
-
| `colors` | `
|
|
229
|
-
| `clickable` | `boolean` | `false` |
|
|
230
|
-
| `selected` | `boolean` | `false` |
|
|
231
|
-
| `scrollable` | `boolean` | `false` |
|
|
232
|
-
| `fullHeight` | `boolean` | `false` |
|
|
245
|
+
| `variant` | `CardVariant` | `'outlined'` | |
|
|
246
|
+
| `padding` | `CardPadding` | `'md'` | |
|
|
247
|
+
| `colors` | `CardColors` | `'primary'` | |
|
|
248
|
+
| `clickable` | `boolean` | `false` | |
|
|
249
|
+
| `selected` | `boolean` | `false` | |
|
|
250
|
+
| `scrollable` | `boolean` | `false` | |
|
|
251
|
+
| `fullHeight` | `boolean` | `false` | |
|
|
233
252
|
|
|
234
|
-
|
|
253
|
+
#### Outputs
|
|
235
254
|
|
|
236
|
-
| Output |
|
|
255
|
+
| Output | Emitter type | Description |
|
|
237
256
|
|---|---|---|
|
|
238
|
-
| `clicked` | `void
|
|
257
|
+
| `clicked` | `OutputEmitterRef<void>` | |
|
|
239
258
|
|
|
240
259
|
---
|
|
260
|
+
### 5.3 `IconActionButtonComponent`
|
|
241
261
|
|
|
242
|
-
|
|
262
|
+
**Selector:** `keepui-icon-action-button`
|
|
263
|
+
**Import:** `import { IconActionButtonComponent } from '@keepui/ui';`
|
|
243
264
|
|
|
244
|
-
|
|
265
|
+
Circular icon-only action button with `default` and `danger` variants,
|
|
266
|
+
loading state, and full accessibility support.
|
|
245
267
|
|
|
246
|
-
|
|
268
|
+
Because this button renders no visible text, `ariaLabel` is **required** to
|
|
269
|
+
satisfy WCAG 2.1 SC 4.1.2 (Name, Role, Value).
|
|
270
|
+
|
|
271
|
+
The icon color is inherited automatically via `currentColor` from the button's
|
|
272
|
+
text color, so SVG symbols defined with `stroke="currentColor"` will adapt to
|
|
273
|
+
both variants and themes without extra classes.
|
|
247
274
|
|
|
248
275
|
```html
|
|
249
|
-
|
|
250
|
-
<keepui-icon name="check-icon" [size]="20" />
|
|
276
|
+
<keepui-icon-action-button icon="edit-icon" ariaLabel="Editar" />
|
|
251
277
|
|
|
252
|
-
|
|
253
|
-
|
|
278
|
+
<keepui-icon-action-button
|
|
279
|
+
icon="trash-icon"
|
|
280
|
+
variant="danger"
|
|
281
|
+
ariaLabel="Eliminar elemento"
|
|
282
|
+
[loading]="isDeleting()"
|
|
283
|
+
/>
|
|
284
|
+
```
|
|
254
285
|
|
|
255
|
-
|
|
256
|
-
<keepui-button variant="primary" size="auto">
|
|
257
|
-
<keepui-icon slot="leading" name="add-icon" [size]="16" />
|
|
258
|
-
New item
|
|
259
|
-
</keepui-button>
|
|
286
|
+
#### Inputs
|
|
260
287
|
|
|
261
|
-
|
|
262
|
-
|
|
288
|
+
| Input | Type | Default | Description |
|
|
289
|
+
|---|---|---|---|
|
|
290
|
+
| `icon` | `unknown` | — | ID of the SVG symbol to render (without the `#` prefix). |
|
|
291
|
+
| `ariaLabel` | `unknown` | — | Accessible label for the button. Always required — icon-only buttons must
|
|
292
|
+
have a programmatic name for screen readers (WCAG 2.1 SC 4.1.2). |
|
|
293
|
+
| `variant` | `IconActionButtonVariant` | `'default'` | Visual style variant. |
|
|
294
|
+
| `iconSize` | `number` | `20` | Size of the inner icon in pixels. |
|
|
295
|
+
| `type` | `IconActionButtonType` | `'button'` | HTML `type` attribute of the inner `<button>`. |
|
|
296
|
+
| `disabled` | `boolean` | `false` | Disables the button when `true`. |
|
|
297
|
+
| `loading` | `boolean` | `false` | Shows an animated spinner and disables the button.
|
|
298
|
+
Also sets `aria-busy="true"` on the element. |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
### 5.4 `IconComponent`
|
|
302
|
+
|
|
303
|
+
**Selector:** `keepui-icon`
|
|
304
|
+
**Import:** `import { IconComponent } from '@keepui/ui';`
|
|
305
|
+
|
|
306
|
+
Generic SVG sprite icon renderer.
|
|
307
|
+
|
|
308
|
+
Renders a `<use href="#name">` reference pointing to an SVG symbol pre-registered
|
|
309
|
+
in the DOM by the consuming application (e.g. via `IconRegistryService`).
|
|
310
|
+
|
|
311
|
+
Accessibility:
|
|
312
|
+
- When used decoratively (default), the SVG carries `aria-hidden="true"` automatically.
|
|
313
|
+
- When used as a standalone meaningful icon, supply an `ariaLabel` — the SVG will
|
|
314
|
+
receive `role="img"` and `aria-label` accordingly.
|
|
315
|
+
|
|
316
|
+
```html
|
|
317
|
+
<!-- Decorative — hidden from screen readers -->
|
|
318
|
+
<keepui-icon name="check-icon" [size]="20" aria-hidden="true" />
|
|
319
|
+
|
|
320
|
+
<!-- Meaningful standalone icon -->
|
|
321
|
+
<keepui-icon name="close-icon" ariaLabel="Cerrar" />
|
|
263
322
|
```
|
|
264
323
|
|
|
265
|
-
|
|
324
|
+
#### Inputs
|
|
266
325
|
|
|
267
326
|
| Input | Type | Default | Description |
|
|
268
327
|
|---|---|---|---|
|
|
269
|
-
| `name`
|
|
328
|
+
| `name` | `unknown` | — | ID of the SVG symbol to render (without the `#` prefix). |
|
|
270
329
|
| `size` | `number` | `24` | Width and height of the icon in pixels. |
|
|
271
330
|
| `viewBox` | `string` | `'0 0 24 24'` | `viewBox` attribute forwarded to the `<svg>` element. |
|
|
272
|
-
| `ariaLabel` | `string` | `''` |
|
|
331
|
+
| `ariaLabel` | `string` | `''` | Accessible label for standalone icons.
|
|
332
|
+
When provided, sets `role="img"` and `aria-label` on the SVG.
|
|
333
|
+
When omitted, the SVG is marked `aria-hidden="true"` (decorative). |
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
### 5.5 `ImagePreviewComponent`
|
|
273
337
|
|
|
274
|
-
|
|
338
|
+
**Selector:** `keepui-image-preview`
|
|
339
|
+
**Import:** `import { ImagePreviewComponent } from '@keepui/ui';`
|
|
340
|
+
|
|
341
|
+
Standalone component that allows the user to pick and preview an image.
|
|
342
|
+
|
|
343
|
+
This component is fully platform-agnostic. It delegates file picking to
|
|
344
|
+
whatever `FilePort` implementation is provided via `FILE_PORT`.
|
|
345
|
+
|
|
346
|
+
UI strings are fully internationalised via Transloco (scope `'keepui'`).
|
|
347
|
+
Call `provideKeepUiI18n()` in your `app.config.ts` and use
|
|
348
|
+
`KeepUiLanguageService.setLanguage(lang)` to change locale at runtime.
|
|
349
|
+
|
|
350
|
+
Usage:
|
|
351
|
+
```html
|
|
352
|
+
<keepui-image-preview />
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Prerequisites — register providers in `app.config.ts`:
|
|
356
|
+
- Web: `provideKeepUi()` + `provideKeepUiI18n()`
|
|
357
|
+
- Capacitor: `provideKeepUiCapacitor()` + `provideKeepUiI18n()`
|
|
358
|
+
|
|
359
|
+
#### Public signals (readable from outside)
|
|
360
|
+
|
|
361
|
+
| Signal | Type | Description |
|
|
362
|
+
|---|---|---|
|
|
363
|
+
| `imageUrl` | `Signal<string | null>` | URL of the selected image, ready to bind to `[src]`. |
|
|
364
|
+
| `error` | `Signal<string | null>` | Error message if the last pick operation failed. |
|
|
365
|
+
| `loading` | `Signal<boolean>` | True while the pick operation is in progress. |
|
|
275
366
|
|
|
276
367
|
---
|
|
368
|
+
### 5.6 `SignalDropdownComponent`
|
|
277
369
|
|
|
278
|
-
|
|
370
|
+
**Selector:** `keepui-signal-dropdown`
|
|
371
|
+
**Import:** `import { SignalDropdownComponent } from '@keepui/ui';`
|
|
279
372
|
|
|
280
|
-
|
|
373
|
+
Signal-based accessible dropdown / select component.
|
|
281
374
|
|
|
282
|
-
|
|
375
|
+
Fully platform-agnostic — no native API usage. The panel opens in `fixed`
|
|
376
|
+
position so it is never clipped by overflow-hidden ancestors. It repositions
|
|
377
|
+
itself automatically on scroll and resize.
|
|
378
|
+
|
|
379
|
+
The `value` and `touched` properties are `model()` signals so the component
|
|
380
|
+
integrates seamlessly with Angular signal-based forms.
|
|
283
381
|
|
|
284
382
|
```html
|
|
285
|
-
|
|
286
|
-
|
|
383
|
+
<keepui-signal-dropdown
|
|
384
|
+
label="País"
|
|
385
|
+
placeholder="Selecciona un país"
|
|
386
|
+
[options]="countries"
|
|
387
|
+
[(value)]="selectedCountry"
|
|
388
|
+
/>
|
|
389
|
+
```
|
|
287
390
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
391
|
+
#### Inputs
|
|
392
|
+
|
|
393
|
+
| Input | Type | Default | Description |
|
|
394
|
+
|---|---|---|---|
|
|
395
|
+
| `label` | `string` | `''` | Optional label text rendered above the dropdown. |
|
|
396
|
+
| `placeholder` | `string` | `''` | Placeholder shown when no value is selected. |
|
|
397
|
+
| `options` | `unknown` | — | Array of options to display in the panel. |
|
|
398
|
+
| `width` | `SignalDropdownWidth` | `'full'` | Layout width of the wrapper. |
|
|
399
|
+
| `required` | `boolean` | `false` | Marks the field as required. Adds `aria-required` and a visual asterisk. |
|
|
400
|
+
| `errorMessage` | `string` | `''` | Human-readable error message shown below the dropdown. Takes precedence over `errors[0]`. |
|
|
401
|
+
| `errors` | `readonly string[]` | `[]` | Array of error strings. The first item is displayed when `errorMessage` is empty.
|
|
402
|
+
Set together with `invalid=true` to trigger the error state. |
|
|
403
|
+
| `selectId` | `string` | ``ku-dropdown-${Math.random(` | Stable `id` used to link the `<label>` with the trigger `<button>`.
|
|
404
|
+
A random suffix is generated by default. |
|
|
405
|
+
| `disabled` | `boolean` | `false` | Disables the dropdown. |
|
|
406
|
+
| `invalid` | `boolean` | `false` | Forces the error visual state regardless of the `touched` model.
|
|
407
|
+
Useful for external form validation. |
|
|
408
|
+
|
|
409
|
+
#### Outputs
|
|
410
|
+
|
|
411
|
+
| Output | Emitter type | Description |
|
|
412
|
+
|---|---|---|
|
|
413
|
+
| `valueChange` | `OutputEmitterRef<T | null>` | Emitted when the selected value changes. |
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
### 5.7 `SignalTextareaComponent`
|
|
417
|
+
|
|
418
|
+
**Selector:** `keepui-signal-textarea`
|
|
419
|
+
**Import:** `import { SignalTextareaComponent } from '@keepui/ui';`
|
|
420
|
+
|
|
421
|
+
Signal-based accessible textarea component with character counter,
|
|
422
|
+
resize control, and integrated error display.
|
|
423
|
+
|
|
424
|
+
The `value` and `touched` properties are `model()` signals so the component
|
|
425
|
+
integrates seamlessly with Angular signal-based forms.
|
|
426
|
+
|
|
427
|
+
```html
|
|
428
|
+
<keepui-signal-textarea
|
|
429
|
+
label="Descripción"
|
|
430
|
+
placeholder="Escribe aquí…"
|
|
431
|
+
[rows]="5"
|
|
432
|
+
[maxLength]="500"
|
|
433
|
+
[(value)]="description"
|
|
293
434
|
/>
|
|
435
|
+
```
|
|
294
436
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
437
|
+
#### Inputs
|
|
438
|
+
|
|
439
|
+
| Input | Type | Default | Description |
|
|
440
|
+
|---|---|---|---|
|
|
441
|
+
| `label` | `string` | `''` | Optional label text rendered above the textarea. |
|
|
442
|
+
| `placeholder` | `string` | `''` | Placeholder passed to the underlying `<textarea>`. |
|
|
443
|
+
| `rows` | `number` | `4` | Number of visible text rows. |
|
|
444
|
+
| `width` | `SignalTextareaWidth` | `'full'` | Layout width of the wrapper. |
|
|
445
|
+
| `resize` | `SignalTextareaResize` | `'none'` | CSS `resize` behaviour. |
|
|
446
|
+
| `required` | `boolean` | `false` | Marks the field as required. |
|
|
447
|
+
| `errorMessage` | `string` | `''` | Human-readable error message. Takes precedence over `errors[0]`. |
|
|
448
|
+
| `errors` | `readonly string[]` | `[]` | Array of error strings. The first item is displayed when `errorMessage` is empty.
|
|
449
|
+
Set together with `invalid=true` to trigger the error state. |
|
|
450
|
+
| `textareaId` | `string` | ``ku-textarea-${Math.random(` | Stable `id` used to link the `<label>` with the `<textarea>`.
|
|
451
|
+
A random suffix is generated by default. |
|
|
452
|
+
| `disabled` | `boolean` | `false` | Disables the textarea. |
|
|
453
|
+
| `maxLength` | `number | undefined` | `undefined` | Maximum number of characters allowed. Shows a character counter when set. |
|
|
454
|
+
| `invalid` | `boolean` | `false` | Forces the error visual state regardless of the `touched` model.
|
|
455
|
+
Useful for external form validation. |
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
### 5.8 `SignalTextInputComponent`
|
|
459
|
+
|
|
460
|
+
**Selector:** `keepui-signal-text-input`
|
|
461
|
+
**Import:** `import { SignalTextInputComponent } from '@keepui/ui';`
|
|
462
|
+
|
|
463
|
+
Signal-based accessible text input supporting all common HTML input types,
|
|
464
|
+
leading/trailing icons, a trailing content slot, and a built-in
|
|
465
|
+
password-visibility toggle (when `type="password"`).
|
|
466
|
+
|
|
467
|
+
The `value` and `touched` properties are `model()` signals so the component
|
|
468
|
+
integrates seamlessly with Angular signal-based forms.
|
|
469
|
+
|
|
470
|
+
Password toggle labels are translated via Transloco (scope `'keepui'`).
|
|
471
|
+
Call `provideKeepUiI18n()` in your `app.config.ts` to activate i18n.
|
|
472
|
+
|
|
473
|
+
```html
|
|
474
|
+
<keepui-signal-text-input
|
|
475
|
+
label="Email"
|
|
476
|
+
type="email"
|
|
477
|
+
placeholder="usuario@ejemplo.com"
|
|
478
|
+
leadingIcon="mail-icon"
|
|
479
|
+
[(value)]="email"
|
|
300
480
|
/>
|
|
301
481
|
|
|
302
|
-
<!--
|
|
303
|
-
<keepui-
|
|
482
|
+
<!-- Password with toggle -->
|
|
483
|
+
<keepui-signal-text-input
|
|
484
|
+
label="Contraseña"
|
|
485
|
+
type="password"
|
|
486
|
+
[(value)]="password"
|
|
487
|
+
/>
|
|
304
488
|
```
|
|
305
489
|
|
|
306
|
-
|
|
490
|
+
#### Inputs
|
|
307
491
|
|
|
308
492
|
| Input | Type | Default | Description |
|
|
309
493
|
|---|---|---|---|
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
|
|
318
|
-
|
|
494
|
+
| `label` | `string` | `''` | Optional label text rendered above the input. |
|
|
495
|
+
| `placeholder` | `string` | `''` | Placeholder passed to the underlying `<input>`. |
|
|
496
|
+
| `type` | `SignalTextInputType` | `'text'` | HTML `type` attribute. Use `'password'` to enable the visibility toggle. |
|
|
497
|
+
| `width` | `SignalTextInputWidth` | `'full'` | Layout width of the wrapper. |
|
|
498
|
+
| `leadingIcon` | `string` | `''` | Name of the leading icon (SVG symbol ID). Leave empty for no icon. |
|
|
499
|
+
| `trailingIcon` | `string` | `''` | Name of the trailing icon (SVG symbol ID). Ignored when `type="password"`. |
|
|
500
|
+
| `hasTrailingSlot` | `boolean` | `false` | When `true`, a slot for custom trailing content is enabled
|
|
501
|
+
(projects `[trailingSlot]` content). Overrides `trailingIcon`. |
|
|
502
|
+
| `required` | `boolean` | `false` | Marks the field as required. Adds `aria-required` and a visual asterisk. |
|
|
503
|
+
| `showRequiredIndicator` | `boolean` | `true` | When `false`, hides the visual asterisk even if `required=true`. |
|
|
504
|
+
| `errorMessage` | `string` | `''` | Human-readable error message. Takes precedence over `errors[0]`. |
|
|
505
|
+
| `errors` | `readonly string[]` | `[]` | Array of error strings. The first item is displayed when `errorMessage` is empty.
|
|
506
|
+
Set together with `invalid=true` to trigger the error state. |
|
|
507
|
+
| `inputId` | `string` | ``ku-text-input-${Math.random(` | Stable `id` used to link the `<label>` with the `<input>`.
|
|
508
|
+
A random suffix is generated by default. |
|
|
509
|
+
| `disabled` | `boolean` | `false` | Disables the input. |
|
|
510
|
+
| `invalid` | `boolean` | `false` | Forces the error visual state regardless of the `touched` model.
|
|
511
|
+
Useful for external form validation. |
|
|
319
512
|
|
|
320
513
|
---
|
|
321
514
|
|
|
322
|
-
|
|
515
|
+
## 6. Type definitions
|
|
323
516
|
|
|
324
|
-
|
|
517
|
+
> Visual style variant of the button.
|
|
325
518
|
|
|
326
|
-
```
|
|
327
|
-
|
|
519
|
+
```ts
|
|
520
|
+
type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
|
|
328
521
|
```
|
|
329
522
|
|
|
330
|
-
|
|
523
|
+
> Size mode of the button.
|
|
524
|
+
- `md`: fixed width (160 px) and height (40 px).
|
|
525
|
+
- `auto`: height fixed (40 px), width grows with padding to fit content.
|
|
331
526
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
527
|
+
```ts
|
|
528
|
+
type ButtonSize = 'md' | 'auto';
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
> Border-radius style of the button.
|
|
532
|
+
- `pill`: fully rounded (`rounded-full`).
|
|
533
|
+
- `rounded`: moderately rounded (`rounded-2xl`).
|
|
534
|
+
|
|
535
|
+
```ts
|
|
536
|
+
type ButtonShape = 'pill' | 'rounded';
|
|
537
|
+
```
|
|
337
538
|
|
|
338
|
-
|
|
539
|
+
> HTML `type` attribute for the underlying `<button>` element.
|
|
339
540
|
|
|
340
541
|
```ts
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
provideKeepUiI18n({ defaultLang: 'en' })
|
|
542
|
+
type ButtonType = 'button' | 'submit' | 'reset';
|
|
543
|
+
```
|
|
344
544
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
provideKeepUiI18n({ defaultLang: 'en' })
|
|
545
|
+
```ts
|
|
546
|
+
type CardVariant = 'flat' | 'outlined';
|
|
348
547
|
```
|
|
349
548
|
|
|
350
|
-
|
|
549
|
+
```ts
|
|
550
|
+
type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'screen';
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
type CardColors = 'primary' | 'secondary';
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
type IconActionButtonVariant = 'default' | 'danger';
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
type IconActionButtonType = 'button' | 'submit' | 'reset';
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
> Layout width of the dropdown wrapper.
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
type SignalDropdownWidth = 'full' | 'half' | 'auto';
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
> Layout width of the text input wrapper.
|
|
572
|
+
|
|
573
|
+
```ts
|
|
574
|
+
type SignalTextInputWidth = 'full' | 'half' | 'auto';
|
|
575
|
+
```
|
|
351
576
|
|
|
352
|
-
|
|
577
|
+
> HTML `type` attribute for the underlying `<input>` element.
|
|
578
|
+
Use `'password'` to enable the built-in show/hide toggle.
|
|
353
579
|
|
|
354
|
-
|
|
580
|
+
```ts
|
|
581
|
+
type SignalTextInputType = | 'text'
|
|
582
|
+
| 'email'
|
|
583
|
+
| 'tel'
|
|
584
|
+
| 'number'
|
|
585
|
+
| 'password'
|
|
586
|
+
| 'search'
|
|
587
|
+
| 'url'
|
|
588
|
+
| 'date';
|
|
589
|
+
```
|
|
355
590
|
|
|
356
|
-
|
|
591
|
+
> Layout width of the textarea wrapper.
|
|
592
|
+
|
|
593
|
+
```ts
|
|
594
|
+
type SignalTextareaWidth = 'full' | 'half' | 'auto';
|
|
595
|
+
```
|
|
357
596
|
|
|
358
|
-
|
|
597
|
+
> CSS `resize` behaviour of the `<textarea>` element.
|
|
598
|
+
- `none` → not resizable (default).
|
|
599
|
+
- `vertical` → user can drag to resize vertically.
|
|
600
|
+
- `horizontal` → user can drag to resize horizontally.
|
|
601
|
+
- `both` → user can drag freely.
|
|
359
602
|
|
|
360
603
|
```ts
|
|
361
|
-
|
|
604
|
+
type SignalTextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
362
608
|
|
|
363
|
-
|
|
364
|
-
export class MyComponent {
|
|
365
|
-
private readonly langService = inject(KeepUiLanguageService);
|
|
609
|
+
## 7. Interfaces & models
|
|
366
610
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
611
|
+
### `FileResult`
|
|
612
|
+
|
|
613
|
+
Represents the result of a file/image selection operation.
|
|
614
|
+
This model is platform-agnostic and used across all adapters.
|
|
615
|
+
|
|
616
|
+
```ts
|
|
617
|
+
interface FileResult {
|
|
618
|
+
/** A data URL (e.g. `data:image/jpeg;base64,...`) or an HTTP/file URL ready to display. */
|
|
619
|
+
dataUrl: string;
|
|
620
|
+
/** MIME type of the selected file, e.g. `image/jpeg`. */
|
|
621
|
+
mimeType: string;
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### `FilePort`
|
|
626
|
+
|
|
627
|
+
Platform-agnostic port (interface) for file/image selection.
|
|
628
|
+
|
|
629
|
+
Provide a concrete implementation via the `FILE_PORT` injection token.
|
|
630
|
+
- Web: `WebFileService`
|
|
631
|
+
- Capacitor: `CapacitorFileService` (from `@keepui/ui/capacitor`)
|
|
632
|
+
|
|
633
|
+
```ts
|
|
634
|
+
interface FilePort {
|
|
635
|
+
/** Opens a platform-native image picker and returns the selected image.
|
|
636
|
+
Resolves with a `FileResult` containing a displayable URL and MIME type.
|
|
637
|
+
Rejects if the user cancels or an error occurs. */
|
|
638
|
+
pickImage(): Promise<FileResult>;
|
|
370
639
|
}
|
|
371
640
|
```
|
|
372
641
|
|
|
373
642
|
---
|
|
374
643
|
|
|
375
|
-
##
|
|
644
|
+
## 8. Services
|
|
376
645
|
|
|
377
|
-
|
|
646
|
+
### `KeepUiLanguageService`
|
|
378
647
|
|
|
379
|
-
|
|
648
|
+
Service that exposes a public API for changing the active language of all
|
|
649
|
+
KeepUI components at runtime.
|
|
380
650
|
|
|
651
|
+
### Usage
|
|
381
652
|
```ts
|
|
382
|
-
|
|
653
|
+
// Inject anywhere in the host application
|
|
654
|
+
const lang = inject(KeepUiLanguageService);
|
|
655
|
+
|
|
656
|
+
// Switch to Spanish
|
|
657
|
+
lang.setLanguage('es');
|
|
658
|
+
|
|
659
|
+
// Read the active language
|
|
660
|
+
console.log(lang.activeLanguage()); // 'es'
|
|
383
661
|
```
|
|
384
662
|
|
|
385
|
-
|
|
663
|
+
Register via `provideKeepUiI18n()` in `app.config.ts`.
|
|
664
|
+
|
|
665
|
+
**Public properties:**
|
|
666
|
+
|
|
667
|
+
| Property | Type | Description |
|
|
668
|
+
|---|---|---|
|
|
669
|
+
| `activeLanguage` | — | Signal that reflects the currently active KeepUI locale. |
|
|
670
|
+
| `availableLanguages` | `readonly KeepUiLanguage[]` | Ordered list of all supported locales. |
|
|
671
|
+
|
|
672
|
+
**Public methods:**
|
|
673
|
+
|
|
674
|
+
- `setLanguage(lang: KeepUiLanguage): void` — Changes the active language for all KeepUI components.
|
|
675
|
+
|
|
676
|
+
### `WebFileService`
|
|
677
|
+
|
|
678
|
+
Web implementation of `FilePort`.
|
|
679
|
+
|
|
680
|
+
Uses a hidden `<input type="file">` and the `FileReader` API to let the user
|
|
681
|
+
pick an image from the file system in a browser environment.
|
|
682
|
+
|
|
683
|
+
This implementation has no dependency on Capacitor or any native plugin.
|
|
684
|
+
|
|
685
|
+
**Public methods:**
|
|
686
|
+
|
|
687
|
+
- `pickImage(): Promise<FileResult>` —
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## 9. Internationalisation (i18n)
|
|
692
|
+
|
|
693
|
+
Use typed constants instead of raw strings:
|
|
694
|
+
|
|
695
|
+
```ts
|
|
696
|
+
import { KEEPUI_TRANSLATION_KEYS as T } from '@keepui/ui';
|
|
697
|
+
|
|
698
|
+
// Example
|
|
699
|
+
translocoService.translate(T.IMAGE_PREVIEW.SELECT_IMAGE);
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
**Supported languages:** `en` (English), `es` (Spanish), `de` (German)
|
|
703
|
+
|
|
704
|
+
**Translation keys:**
|
|
705
|
+
|
|
706
|
+
| Constant path | Translation key |
|
|
707
|
+
|---|---|
|
|
708
|
+
| `IMAGE_PREVIEW.SELECT_IMAGE` | `imagePreview.selectImage` |
|
|
709
|
+
| `IMAGE_PREVIEW.LOADING` | `imagePreview.loading` |
|
|
710
|
+
| `IMAGE_PREVIEW.PREVIEW_ALT` | `imagePreview.previewAlt` |
|
|
711
|
+
| `IMAGE_PREVIEW.ERROR_UNEXPECTED` | `imagePreview.errorUnexpected` |
|
|
712
|
+
| `SIGNAL_TEXT_INPUT.SHOW_PASSWORD` | `signalTextInput.showPassword` |
|
|
713
|
+
| `SIGNAL_TEXT_INPUT.HIDE_PASSWORD` | `signalTextInput.hidePassword` |
|
|
714
|
+
|
|
715
|
+
**Changing language at runtime:**
|
|
716
|
+
|
|
717
|
+
```ts
|
|
718
|
+
import { KeepUiLanguageService } from '@keepui/ui';
|
|
719
|
+
|
|
720
|
+
const lang = inject(KeepUiLanguageService);
|
|
721
|
+
lang.setLanguage('es'); // 'en' | 'es' | 'de'
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## 10. CSS design tokens
|
|
727
|
+
|
|
728
|
+
Override any variable in your CSS to customise the theme:
|
|
386
729
|
|
|
387
730
|
```css
|
|
388
731
|
:root {
|
|
389
|
-
--
|
|
732
|
+
--keepui-primary: #3b82f6;
|
|
733
|
+
--keepui-primary-hover: #2563eb;
|
|
734
|
+
--keepui-primary-active: #1d4ed8;
|
|
735
|
+
--keepui-primary-foreground: #ffffff;
|
|
736
|
+
--keepui-background: #f5f5f5;
|
|
737
|
+
--keepui-surface: #ffffff;
|
|
738
|
+
--keepui-surface-hover: #f0f0f0;
|
|
739
|
+
--keepui-border: #e0e0e0;
|
|
740
|
+
--keepui-border-strong: #cccccc;
|
|
741
|
+
--keepui-text: #1f2937;
|
|
742
|
+
--keepui-text-muted: #6b7280;
|
|
743
|
+
--keepui-text-disabled: #9ca3af;
|
|
744
|
+
--keepui-error: #dc2626;
|
|
745
|
+
--keepui-error-foreground: #ffffff;
|
|
746
|
+
--keepui-success: #16a34a;
|
|
747
|
+
--keepui-warning: #f59e0b;
|
|
748
|
+
--keepui-shadow-sm: 0 1px 3px rgba(0,0,0,.12);
|
|
749
|
+
--keepui-shadow-md: 0 3px 6px rgba(0,0,0,.15);
|
|
750
|
+
--keepui-shadow-lg: 0 6px 12px rgba(0,0,0,.18);
|
|
390
751
|
}
|
|
391
752
|
|
|
392
753
|
[data-theme="dark"] {
|
|
393
|
-
--
|
|
754
|
+
--keepui-primary: #60a5fa;
|
|
755
|
+
--keepui-primary-foreground: #0f172a;
|
|
756
|
+
--keepui-background: #0f172a;
|
|
757
|
+
--keepui-surface: #1e293b;
|
|
758
|
+
--keepui-surface-hover: #334155;
|
|
759
|
+
--keepui-border: #334155;
|
|
760
|
+
--keepui-border-strong: #475569;
|
|
761
|
+
--keepui-text: #f1f5f9;
|
|
762
|
+
--keepui-text-muted: #94a3b8;
|
|
763
|
+
--keepui-text-disabled: #64748b;
|
|
764
|
+
--keepui-error: #f87171;
|
|
765
|
+
--keepui-error-foreground: #0f172a;
|
|
766
|
+
--keepui-success: #4ade80;
|
|
767
|
+
--keepui-warning: #fbbf24;
|
|
394
768
|
}
|
|
395
769
|
```
|
|
396
770
|
|
|
397
|
-
Refer to the bundled `themes.css` file for the full list of available tokens.
|
|
398
|
-
|
|
399
771
|
---
|
|
400
772
|
|
|
401
|
-
##
|
|
773
|
+
## 11. Tailwind utility classes
|
|
402
774
|
|
|
403
|
-
|
|
775
|
+
Generated automatically after `@import "@keepui/ui/styles"` with Tailwind v4:
|
|
404
776
|
|
|
405
777
|
```
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
778
|
+
bg-keepui-background bg-keepui-surface bg-keepui-surface-hover
|
|
779
|
+
bg-keepui-primary bg-keepui-primary-hover bg-keepui-primary-active
|
|
780
|
+
bg-keepui-error bg-keepui-success bg-keepui-warning
|
|
781
|
+
|
|
782
|
+
text-keepui-text text-keepui-text-muted text-keepui-text-disabled
|
|
783
|
+
text-keepui-primary text-keepui-primary-fg text-keepui-error
|
|
784
|
+
|
|
785
|
+
border-keepui-border border-keepui-border-strong border-keepui-primary
|
|
786
|
+
|
|
787
|
+
shadow-keepui-sm shadow-keepui-md shadow-keepui-lg
|
|
788
|
+
|
|
789
|
+
focus-visible:ring-keepui-primary
|
|
416
790
|
```
|
|
417
791
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
- `provideKeepUiCapacitor()` registers `CapacitorFileService`.
|
|
421
|
-
- Capacitor dependencies are **not** pulled into web builds.
|
|
792
|
+
---
|
|
793
|
+
### 5.10 `TabGroupComponent`
|
|
422
794
|
|
|
423
|
-
|
|
795
|
+
**Selector:** `keepui-tab-group`
|
|
796
|
+
**Import:** `import { TabGroupComponent, Tab, TabGroupVariant } from '@keepui/ui';`
|
|
424
797
|
|
|
425
|
-
|
|
798
|
+
Accessible pill-style tab group implementing the WAI-ARIA `tablist` pattern.
|
|
799
|
+
Supports icons, disabled tabs, keyboard navigation (arrow keys, `Home`, `End`)
|
|
800
|
+
and two visual variants. No internal i18n strings — tab labels are provided
|
|
801
|
+
by the consumer.
|
|
426
802
|
|
|
427
|
-
|
|
803
|
+
```html
|
|
804
|
+
<!-- Default variant -->
|
|
805
|
+
<keepui-tab-group
|
|
806
|
+
[tabs]="tabs"
|
|
807
|
+
[selectedTabId]="activeTab"
|
|
808
|
+
(tabChange)="activeTab = $event"
|
|
809
|
+
ariaLabel="Main sections"
|
|
810
|
+
/>
|
|
428
811
|
|
|
429
|
-
|
|
812
|
+
<!-- Filled variant -->
|
|
813
|
+
<keepui-tab-group
|
|
814
|
+
variant="filled"
|
|
815
|
+
[tabs]="tabs"
|
|
816
|
+
[selectedTabId]="activeTab"
|
|
817
|
+
(tabChange)="activeTab = $event"
|
|
818
|
+
/>
|
|
819
|
+
```
|
|
430
820
|
|
|
431
821
|
```ts
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
822
|
+
readonly tabs: Tab[] = [
|
|
823
|
+
{ id: 'home', label: 'Home' },
|
|
824
|
+
{ id: 'profile', label: 'Profile', icon: 'user-icon' },
|
|
825
|
+
{ id: 'settings', label: 'Settings', disabled: true },
|
|
826
|
+
];
|
|
437
827
|
```
|
|
438
828
|
|
|
829
|
+
#### Inputs
|
|
830
|
+
|
|
831
|
+
| Input | Type | Default | Description |
|
|
832
|
+
|---|---|---|---|
|
|
833
|
+
| `tabs` | `Tab[]` | *(required)* | List of tabs to render. |
|
|
834
|
+
| `selectedTabId` | `string` | *(required)* | ID of the currently active tab. |
|
|
835
|
+
| `variant` | `TabGroupVariant` | `'default'` | Visual style: `'default'` or `'filled'`. |
|
|
836
|
+
| `ariaLabel` | `string` | `''` | Accessible label for the `tablist` element. |
|
|
837
|
+
|
|
838
|
+
#### Outputs
|
|
839
|
+
|
|
840
|
+
| Output | Emitter type | Description |
|
|
841
|
+
|---|---|---|
|
|
842
|
+
| `tabChange` | `OutputEmitterRef<string>` | Emits the `id` of the selected tab. |
|
|
843
|
+
|
|
844
|
+
#### `Tab` interface
|
|
845
|
+
|
|
846
|
+
| Property | Type | Required | Description |
|
|
847
|
+
|---|---|---|---|
|
|
848
|
+
| `id` | `string` | ✅ | Unique identifier. |
|
|
849
|
+
| `label` | `string` | ✅ | Visible tab label. |
|
|
850
|
+
| `icon` | `string` | — | SVG symbol ID (without `#`) for an optional icon. |
|
|
851
|
+
| `disabled` | `boolean` | — | When `true`, the tab is not selectable. Default `false`. |
|
|
852
|
+
|
|
853
|
+
#### Accessibility
|
|
854
|
+
|
|
855
|
+
- Container: `role="tablist"` with optional `aria-label`.
|
|
856
|
+
- Each button: `role="tab"`, `aria-selected`, `aria-disabled`, managed `tabindex`.
|
|
857
|
+
- Keyboard: `ArrowRight`/`ArrowLeft` (and `Down`/`Up`) navigate between tabs; `Home`/`End` jump to extremes.
|
|
858
|
+
- Focus ring: `focus-visible:ring-2 focus-visible:ring-ku-action-primary`.
|
|
859
|
+
- Touch target: `min-h-[2.75rem]` on every tab button.
|
|
860
|
+
|
|
439
861
|
---
|
|
862
|
+
### 5.11 `StepperComponent`
|
|
440
863
|
|
|
441
|
-
|
|
864
|
+
**Selector:** `keepui-stepper`
|
|
865
|
+
**Import:** `import { StepperComponent, StepperStep, StepperSize, StepperOrientation } from '@keepui/ui';`
|
|
442
866
|
|
|
443
|
-
|
|
867
|
+
Visual step-progress indicator with optional interactive navigation.
|
|
868
|
+
Renders numbered circles connected by animated progress bars. Completed steps
|
|
869
|
+
show a check-mark; the active step is highlighted with a ring; future steps are muted.
|
|
870
|
+
Steps can carry an icon that replaces the number.
|
|
444
871
|
|
|
445
|
-
```
|
|
446
|
-
|
|
872
|
+
```html
|
|
873
|
+
<!-- Read-only progress indicator -->
|
|
874
|
+
<keepui-stepper [steps]="steps" [activeIndex]="1" />
|
|
875
|
+
|
|
876
|
+
<!-- Interactive (allows going back to completed steps) -->
|
|
877
|
+
<keepui-stepper
|
|
878
|
+
[steps]="steps"
|
|
879
|
+
[activeIndex]="currentStep"
|
|
880
|
+
(stepChange)="currentStep = $event"
|
|
881
|
+
ariaLabel="Registration process"
|
|
882
|
+
/>
|
|
447
883
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
884
|
+
<!-- Small, vertical -->
|
|
885
|
+
<keepui-stepper
|
|
886
|
+
[steps]="steps"
|
|
887
|
+
[activeIndex]="currentStep"
|
|
888
|
+
size="sm"
|
|
889
|
+
orientation="vertical"
|
|
890
|
+
/>
|
|
452
891
|
```
|
|
453
892
|
|
|
454
|
-
`MockFileService` resolves successfully by default. Set `nextError` to test error paths:
|
|
455
|
-
|
|
456
893
|
```ts
|
|
457
|
-
|
|
458
|
-
|
|
894
|
+
readonly steps: StepperStep[] = [
|
|
895
|
+
{ id: '1', label: 'Account' },
|
|
896
|
+
{ id: '2', label: 'Profile', icon: 'user-icon' },
|
|
897
|
+
{ id: '3', label: 'Plan' },
|
|
898
|
+
{ id: '4', label: 'Confirm', disabled: true },
|
|
899
|
+
];
|
|
459
900
|
```
|
|
460
901
|
|
|
461
|
-
|
|
902
|
+
#### Inputs
|
|
462
903
|
|
|
463
|
-
|
|
904
|
+
| Input | Type | Default | Description |
|
|
905
|
+
|---|---|---|---|
|
|
906
|
+
| `steps` | `StepperStep[]` | *(required)* | List of steps to render. |
|
|
907
|
+
| `activeIndex` | `number` | `0` | Zero-based index of the currently active step. |
|
|
908
|
+
| `size` | `StepperSize` | `'md'` | Size of step circles and connectors: `'md'` or `'sm'`. |
|
|
909
|
+
| `orientation` | `StepperOrientation` | `'horizontal'` | Layout direction: `'horizontal'` or `'vertical'`. |
|
|
910
|
+
| `ariaLabel` | `string` | `''` | Accessible label for the `<nav>` element. |
|
|
464
911
|
|
|
465
|
-
|
|
466
|
-
# Production build (APF, partial compilation):
|
|
467
|
-
npm run build
|
|
912
|
+
#### Outputs
|
|
468
913
|
|
|
469
|
-
|
|
470
|
-
|
|
914
|
+
| Output | Emitter type | Description |
|
|
915
|
+
|---|---|---|
|
|
916
|
+
| `stepChange` | `OutputEmitterRef<number>` | Emits the zero-based index of the clicked step (completed or active steps only). |
|
|
471
917
|
|
|
472
|
-
|
|
473
|
-
npm run build:schematics
|
|
918
|
+
#### `StepperStep` interface
|
|
474
919
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
920
|
+
| Property | Type | Required | Description |
|
|
921
|
+
|---|---|---|---|
|
|
922
|
+
| `id` | `string` | ✅ | Unique identifier. |
|
|
923
|
+
| `label` | `string` | ✅ | Label shown below the step circle. |
|
|
924
|
+
| `icon` | `string` | — | SVG symbol ID (without `#`) rendered inside the circle instead of the step number. |
|
|
925
|
+
| `disabled` | `boolean` | — | When `true`, the step is not interactive. Default `false`. |
|
|
478
926
|
|
|
479
|
-
|
|
927
|
+
#### Accessibility
|
|
928
|
+
|
|
929
|
+
- Container: `<nav>` with optional `aria-label`.
|
|
930
|
+
- List: `role="list"` / `role="listitem"` with `aria-current="step"` on the active item.
|
|
931
|
+
- Completed and active steps render as `<button>` elements with `aria-label` equal to the step label.
|
|
932
|
+
- Future and disabled steps render as inert `<span>` elements.
|
|
933
|
+
- Focus ring: `focus-visible:ring-2 focus-visible:ring-ku-action-primary`.
|
|
934
|
+
- Touch target: `min-h-[2.75rem] min-w-[2.75rem]` on every interactive step bubble.
|
|
480
935
|
|
|
481
936
|
---
|
|
482
937
|
|
|
483
|
-
##
|
|
938
|
+
## 12. Integration checklist
|
|
484
939
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
940
|
+
- [ ] `@keepui/ui` installed in `package.json`
|
|
941
|
+
- [ ] `@import "@keepui/ui/styles"` in global stylesheet
|
|
942
|
+
- [ ] Tailwind v4 configured (via `@tailwindcss/postcss` or `@tailwindcss/vite`)
|
|
943
|
+
- [ ] `provideKeepUi()` **or** `provideKeepUiCapacitor()` registered in `app.config.ts`
|
|
944
|
+
- [ ] `provideKeepUiI18n()` registered in `app.config.ts`
|
|
945
|
+
- [ ] Components imported individually in each standalone component or NgModule
|
|
946
|
+
- [ ] `[data-theme="dark"]` toggle wired if dark mode switching is needed
|
|
947
|
+
- [ ] `KeepUiLanguageService.setLanguage()` called if runtime i18n is needed
|
|
948
|
+
|
|
949
|
+
---
|
|
490
950
|
|
|
491
|
-
|
|
951
|
+
## 13. What NOT to do
|
|
492
952
|
|
|
953
|
+
- Do **not** import from `@keepui/ui/src/lib/...` — only from `@keepui/ui` or `@keepui/ui/capacitor`.
|
|
954
|
+
- Do **not** call both `provideKeepUi()` and `provideKeepUiCapacitor()`.
|
|
955
|
+
- Do **not** hardcode `FILE_PORT` implementations inside components — always use the token.
|
|
956
|
+
- Do **not** skip `@import "@keepui/ui/styles"` — without it, all theme utility classes are missing.
|
|
957
|
+
- Do **not** import `@capacitor/*` in code that also imports `@keepui/ui` core.
|