yukit-web 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/.npm/_logs/2026-08-20T08_40_55_706Z-debug-0.log +38 -0
- package/.npm/_logs/2026-08-20T08_40_56_280Z-debug-0.log +14 -0
- package/README.md +1465 -0
- package/fesm2022/yukit-web-helm-accordion.mjs +141 -0
- package/fesm2022/yukit-web-helm-accordion.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-alert-dialog.mjs +250 -0
- package/fesm2022/yukit-web-helm-alert-dialog.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-alert.mjs +94 -0
- package/fesm2022/yukit-web-helm-alert.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-aspect-ratio.mjs +47 -0
- package/fesm2022/yukit-web-helm-aspect-ratio.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-attachment.mjs +211 -0
- package/fesm2022/yukit-web-helm-attachment.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-autocomplete.mjs +361 -0
- package/fesm2022/yukit-web-helm-autocomplete.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-avatar.mjs +152 -0
- package/fesm2022/yukit-web-helm-avatar.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-badge.mjs +47 -0
- package/fesm2022/yukit-web-helm-badge.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-breadcrumb.mjs +196 -0
- package/fesm2022/yukit-web-helm-breadcrumb.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-bubble.mjs +121 -0
- package/fesm2022/yukit-web-helm-bubble.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-button-group.mjs +86 -0
- package/fesm2022/yukit-web-helm-button-group.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-button.mjs +77 -0
- package/fesm2022/yukit-web-helm-button.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-calendar.mjs +937 -0
- package/fesm2022/yukit-web-helm-calendar.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-card.mjs +141 -0
- package/fesm2022/yukit-web-helm-card.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-carousel.mjs +270 -0
- package/fesm2022/yukit-web-helm-carousel.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-checkbox.mjs +147 -0
- package/fesm2022/yukit-web-helm-checkbox.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-collapsible.mjs +62 -0
- package/fesm2022/yukit-web-helm-collapsible.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-combobox.mjs +624 -0
- package/fesm2022/yukit-web-helm-combobox.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-command.mjs +315 -0
- package/fesm2022/yukit-web-helm-command.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-context-menu.mjs +71 -0
- package/fesm2022/yukit-web-helm-context-menu.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-date-picker.mjs +1517 -0
- package/fesm2022/yukit-web-helm-date-picker.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-dialog.mjs +271 -0
- package/fesm2022/yukit-web-helm-dialog.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-drawer.mjs +233 -0
- package/fesm2022/yukit-web-helm-drawer.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-dropdown-menu.mjs +508 -0
- package/fesm2022/yukit-web-helm-dropdown-menu.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-empty.mjs +125 -0
- package/fesm2022/yukit-web-helm-empty.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-field.mjs +325 -0
- package/fesm2022/yukit-web-helm-field.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-hover-card.mjs +102 -0
- package/fesm2022/yukit-web-helm-hover-card.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-input-group.mjs +171 -0
- package/fesm2022/yukit-web-helm-input-group.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-input-otp.mjs +127 -0
- package/fesm2022/yukit-web-helm-input-otp.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-input.mjs +32 -0
- package/fesm2022/yukit-web-helm-input.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-item.mjs +242 -0
- package/fesm2022/yukit-web-helm-item.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-kbd.mjs +46 -0
- package/fesm2022/yukit-web-helm-kbd.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-label.mjs +30 -0
- package/fesm2022/yukit-web-helm-label.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-marker.mjs +77 -0
- package/fesm2022/yukit-web-helm-marker.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-menubar.mjs +90 -0
- package/fesm2022/yukit-web-helm-menubar.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-message.mjs +115 -0
- package/fesm2022/yukit-web-helm-message.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-native-select.mjs +180 -0
- package/fesm2022/yukit-web-helm-native-select.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-navigation-menu.mjs +173 -0
- package/fesm2022/yukit-web-helm-navigation-menu.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-pagination.mjs +745 -0
- package/fesm2022/yukit-web-helm-pagination.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-popover.mjs +136 -0
- package/fesm2022/yukit-web-helm-popover.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-progress.mjs +60 -0
- package/fesm2022/yukit-web-helm-progress.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-radio-group.mjs +185 -0
- package/fesm2022/yukit-web-helm-radio-group.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-resizable.mjs +98 -0
- package/fesm2022/yukit-web-helm-resizable.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-scroll-area.mjs +36 -0
- package/fesm2022/yukit-web-helm-scroll-area.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-select.mjs +412 -0
- package/fesm2022/yukit-web-helm-select.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-separator.mjs +33 -0
- package/fesm2022/yukit-web-helm-separator.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-sheet.mjs +254 -0
- package/fesm2022/yukit-web-helm-sheet.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-sidebar.mjs +857 -0
- package/fesm2022/yukit-web-helm-sidebar.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-skeleton.mjs +29 -0
- package/fesm2022/yukit-web-helm-skeleton.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-slider.mjs +123 -0
- package/fesm2022/yukit-web-helm-slider.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-sonner.mjs +126 -0
- package/fesm2022/yukit-web-helm-sonner.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-spinner.mjs +48 -0
- package/fesm2022/yukit-web-helm-spinner.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-switch.mjs +126 -0
- package/fesm2022/yukit-web-helm-switch.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-table.mjs +180 -0
- package/fesm2022/yukit-web-helm-table.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-tabs.mjs +251 -0
- package/fesm2022/yukit-web-helm-tabs.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-textarea.mjs +32 -0
- package/fesm2022/yukit-web-helm-textarea.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-toggle-group.mjs +95 -0
- package/fesm2022/yukit-web-helm-toggle-group.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-toggle.mjs +61 -0
- package/fesm2022/yukit-web-helm-toggle.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-tooltip.mjs +57 -0
- package/fesm2022/yukit-web-helm-tooltip.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-typography.mjs +205 -0
- package/fesm2022/yukit-web-helm-typography.mjs.map +1 -0
- package/fesm2022/yukit-web-helm-utils.mjs +272 -0
- package/fesm2022/yukit-web-helm-utils.mjs.map +1 -0
- package/fesm2022/yukit-web.mjs +3592 -0
- package/fesm2022/yukit-web.mjs.map +1 -0
- package/package.json +291 -0
- package/src/lib/theme/spartan-overwrites/accordion.css +4 -0
- package/src/lib/theme/theme.css +161 -0
- package/src/lib/theme/tokens/color.css +356 -0
- package/src/lib/theme/tokens/component-colors.css +167 -0
- package/src/lib/theme/tokens/radius.css +18 -0
- package/src/lib/theme/tokens/typography.css +201 -0
- package/types/yukit-web-helm-accordion.d.ts +32 -0
- package/types/yukit-web-helm-alert-dialog.d.ts +85 -0
- package/types/yukit-web-helm-alert.d.ts +37 -0
- package/types/yukit-web-helm-aspect-ratio.d.ts +16 -0
- package/types/yukit-web-helm-attachment.d.ts +80 -0
- package/types/yukit-web-helm-autocomplete.d.ts +91 -0
- package/types/yukit-web-helm-avatar.d.ts +45 -0
- package/types/yukit-web-helm-badge.d.ts +19 -0
- package/types/yukit-web-helm-breadcrumb.d.ts +52 -0
- package/types/yukit-web-helm-bubble.d.ts +46 -0
- package/types/yukit-web-helm-button-group.d.ts +25 -0
- package/types/yukit-web-helm-button.d.ts +33 -0
- package/types/yukit-web-helm-calendar.d.ts +89 -0
- package/types/yukit-web-helm-card.d.ts +49 -0
- package/types/yukit-web-helm-carousel.d.ts +79 -0
- package/types/yukit-web-helm-checkbox.d.ts +60 -0
- package/types/yukit-web-helm-collapsible.d.ts +22 -0
- package/types/yukit-web-helm-combobox.d.ts +150 -0
- package/types/yukit-web-helm-command.d.ts +84 -0
- package/types/yukit-web-helm-context-menu.d.ts +29 -0
- package/types/yukit-web-helm-date-picker.d.ts +574 -0
- package/types/yukit-web-helm-dialog.d.ts +90 -0
- package/types/yukit-web-helm-drawer.d.ts +71 -0
- package/types/yukit-web-helm-dropdown-menu.d.ts +171 -0
- package/types/yukit-web-helm-empty.d.ts +49 -0
- package/types/yukit-web-helm-field.d.ts +102 -0
- package/types/yukit-web-helm-hover-card.d.ts +31 -0
- package/types/yukit-web-helm-input-group.d.ts +47 -0
- package/types/yukit-web-helm-input-otp.d.ts +40 -0
- package/types/yukit-web-helm-input.d.ts +13 -0
- package/types/yukit-web-helm-item.d.ts +96 -0
- package/types/yukit-web-helm-kbd.d.ts +17 -0
- package/types/yukit-web-helm-label.d.ts +12 -0
- package/types/yukit-web-helm-marker.d.ts +31 -0
- package/types/yukit-web-helm-menubar.d.ts +35 -0
- package/types/yukit-web-helm-message.d.ts +44 -0
- package/types/yukit-web-helm-native-select.d.ts +65 -0
- package/types/yukit-web-helm-navigation-menu.d.ts +49 -0
- package/types/yukit-web-helm-pagination.d.ts +187 -0
- package/types/yukit-web-helm-popover.d.ts +49 -0
- package/types/yukit-web-helm-progress.d.ts +22 -0
- package/types/yukit-web-helm-radio-group.d.ts +66 -0
- package/types/yukit-web-helm-resizable.d.ts +27 -0
- package/types/yukit-web-helm-scroll-area.d.ts +11 -0
- package/types/yukit-web-helm-select.d.ts +114 -0
- package/types/yukit-web-helm-separator.d.ts +13 -0
- package/types/yukit-web-helm-sheet.d.ts +75 -0
- package/types/yukit-web-helm-sidebar.d.ts +232 -0
- package/types/yukit-web-helm-skeleton.d.ts +11 -0
- package/types/yukit-web-helm-slider.d.ts +14 -0
- package/types/yukit-web-helm-sonner.d.ts +52 -0
- package/types/yukit-web-helm-spinner.d.ts +18 -0
- package/types/yukit-web-helm-switch.d.ts +54 -0
- package/types/yukit-web-helm-table.d.ts +82 -0
- package/types/yukit-web-helm-tabs.d.ts +66 -0
- package/types/yukit-web-helm-textarea.d.ts +13 -0
- package/types/yukit-web-helm-toggle-group.d.ts +34 -0
- package/types/yukit-web-helm-toggle.d.ts +22 -0
- package/types/yukit-web-helm-tooltip.d.ts +17 -0
- package/types/yukit-web-helm-typography.d.ts +89 -0
- package/types/yukit-web-helm-utils.d.ts +44 -0
- package/types/yukit-web.d.ts +2426 -0
package/README.md
ADDED
|
@@ -0,0 +1,1465 @@
|
|
|
1
|
+
# yukit-web
|
|
2
|
+
|
|
3
|
+
Angular UI component library for Yurest web applications. Built on [Spartan](https://spartan.ng)
|
|
4
|
+
(Tailwind CSS v4 + `@spartan-ng/brain`) and themed with the Yurest design tokens.
|
|
5
|
+
|
|
6
|
+
## Table of contents
|
|
7
|
+
|
|
8
|
+
- [Requirements](#requirements)
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Setup](#setup)
|
|
11
|
+
- [Quick start](#quick-start)
|
|
12
|
+
- [Theming](#theming)
|
|
13
|
+
- [Conventions](#conventions)
|
|
14
|
+
- [Components](#components)
|
|
15
|
+
- [Utilities and services](#utilities-and-services)
|
|
16
|
+
- [Development](#development)
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
| Dependency | Version | Notes |
|
|
21
|
+
|:------------------------------------------------------------------|:----------|:-----------------------------------|
|
|
22
|
+
| [Angular](https://angular.dev/) | 21+ | Standalone APIs, signal inputs |
|
|
23
|
+
| [Tailwind CSS](https://tailwindcss.com/) | v4 | Required — see [Setup](#setup) |
|
|
24
|
+
| [`@spartan-ng/brain`](https://spartan.ng) | ^1.3.0 | Headless primitives |
|
|
25
|
+
| [`@angular/cdk`](https://material.angular.dev/cdk/categories) | ^21.0.0 | Overlays, a11y |
|
|
26
|
+
| [`@ng-icons/core`](https://ng-icons.github.io/ng-icons/) + lucide | ^32.2.0 | Icons |
|
|
27
|
+
| [`@tanstack/angular-table`](https://tanstack.com/table) | ^9.0.0 | `<yuw-datatable>` |
|
|
28
|
+
| `embla-carousel-angular` | ^21.0.0 | Carousel primitives |
|
|
29
|
+
| `ngx-scrollbar` | ^19.1.5 | Scroll areas |
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install yukit-web \
|
|
35
|
+
@spartan-ng/brain @angular/cdk @tanstack/angular-table \
|
|
36
|
+
@ng-icons/core @ng-icons/lucide embla-carousel-angular ngx-scrollbar
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Plus the Tailwind toolchain, as dev dependencies:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -D tailwindcss @tailwindcss/postcss tw-animate-css
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`tw-animate-css` is required because `@spartan-ng/brain/hlm-tailwind-preset.css` imports it.
|
|
46
|
+
|
|
47
|
+
## Setup
|
|
48
|
+
|
|
49
|
+
`yukit-web` does **not** ship compiled component CSS. Its templates carry Tailwind utility classes,
|
|
50
|
+
and your Tailwind build is what turns them into real styles. Two things have to be true in your
|
|
51
|
+
app, or the components render unstyled.
|
|
52
|
+
|
|
53
|
+
### 1. Set up `styles.css`
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
@layer theme, base, components, utilities;
|
|
57
|
+
|
|
58
|
+
@import "tailwindcss";
|
|
59
|
+
@import "@spartan-ng/brain/hlm-tailwind-preset.css";
|
|
60
|
+
@import "yukit-web/theme.css";
|
|
61
|
+
|
|
62
|
+
@source "../node_modules/yukit-web";
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Order matters:
|
|
66
|
+
|
|
67
|
+
| Line | Why |
|
|
68
|
+
|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
69
|
+
| `@layer …` | Fixes layer precedence before anything registers into a layer. |
|
|
70
|
+
| `@import "tailwindcss"` | Must come first — everything below extends it. |
|
|
71
|
+
| Spartan preset | Maps token *names* (`--primary`, `--radius`, …) onto Tailwind utilities and registers Spartan's variants (`data-open`, `data-checked`, …). |
|
|
72
|
+
| `yukit-web/theme.css` | Supplies the Yurest token *values*. Without the preset above it, the custom properties exist but no utilities are generated. |
|
|
73
|
+
| `@source` | **Required.** Tailwind only generates the classes it can see. `yukit-web`'s classes live inside the published package, which Tailwind does not scan by default. |
|
|
74
|
+
|
|
75
|
+
Adjust the `@source` path so it resolves from the file it is written in — the example assumes
|
|
76
|
+
`src/styles.css` with `node_modules` one level up.
|
|
77
|
+
|
|
78
|
+
**If you skip `@source`, the components render with no styling at all.** That is the expected
|
|
79
|
+
failure mode, not a bug: nothing is missing from the package, Tailwind simply never saw it.
|
|
80
|
+
`node_modules` being gitignored does not prevent the scan — an explicit `@source` overrides that.
|
|
81
|
+
|
|
82
|
+
### 2. Enable the Tailwind PostCSS plugin
|
|
83
|
+
|
|
84
|
+
`.postcssrc.json` at the project root:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"plugins": {
|
|
89
|
+
"@tailwindcss/postcss": {}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Icons
|
|
95
|
+
|
|
96
|
+
Components register the icons they need themselves — nothing to configure for `<yuw-badge>`,
|
|
97
|
+
`<yuw-dialog>`, `<yuw-pagination>` and friends to render their own glyphs.
|
|
98
|
+
|
|
99
|
+
You only need `provideIcons` for icons **you** project into a component (`[yuwAlertIcon]`,
|
|
100
|
+
`[yuwItemMedia]`, a button's content, `<yuw-spinner icon="…">`):
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
104
|
+
import { lucideMail, lucidePlus } from '@ng-icons/lucide';
|
|
105
|
+
|
|
106
|
+
@Component({
|
|
107
|
+
imports: [NgIcon, YuwButtonComponent],
|
|
108
|
+
providers: [provideIcons({ lucideMail, lucidePlus })],
|
|
109
|
+
template: `<yuw-button><ng-icon name="lucidePlus" /> New</yuw-button>`,
|
|
110
|
+
})
|
|
111
|
+
export class ExampleComponent {}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Quick start
|
|
115
|
+
|
|
116
|
+
Every export is standalone — import the component classes you use directly.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
|
|
120
|
+
import { YuwButtonComponent, YuwInputComponent, yuwToast, YuwToasterComponent } from 'yukit-web';
|
|
121
|
+
|
|
122
|
+
@Component({
|
|
123
|
+
selector: 'app-login',
|
|
124
|
+
imports: [YuwInputComponent, YuwButtonComponent, YuwToasterComponent],
|
|
125
|
+
template: `
|
|
126
|
+
<yuw-input [(value)]="email" type="email" placeholder="you@yurest.com" />
|
|
127
|
+
<yuw-button color="primary" (clicked)="submit()">Sign in</yuw-button>
|
|
128
|
+
|
|
129
|
+
<yuw-toaster />
|
|
130
|
+
`,
|
|
131
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
132
|
+
})
|
|
133
|
+
export class LoginComponent {
|
|
134
|
+
protected readonly email = signal('');
|
|
135
|
+
|
|
136
|
+
protected submit(): void {
|
|
137
|
+
yuwToast.success('Welcome back');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Theming
|
|
143
|
+
|
|
144
|
+
`yukit-web/theme.css` is the only stylesheet the package exposes. It defines the Yurest palette in
|
|
145
|
+
`oklch` under the token names Spartan expects, so `bg-primary`, `text-muted-foreground`,
|
|
146
|
+
`border-border` and `rounded-lg` resolve to Yurest's design system instead of Spartan's default
|
|
147
|
+
neutral gray.
|
|
148
|
+
|
|
149
|
+
### Extra semantic tokens
|
|
150
|
+
|
|
151
|
+
It also adds Yurest-only semantic colors that Spartan has no equivalent for, registered so they
|
|
152
|
+
behave like any other Tailwind color:
|
|
153
|
+
|
|
154
|
+
| Token | Utilities |
|
|
155
|
+
|:-------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
156
|
+
| `--success` / `--success-foreground` | `bg-success`, `text-success-foreground`, … |
|
|
157
|
+
| `--warning` / `--warning-foreground` | `bg-warning`, `text-warning-foreground`, … |
|
|
158
|
+
| `--info` / `--info-foreground` | `bg-info`, `text-info-foreground`, … |
|
|
159
|
+
| `--destructive-foreground` | `text-destructive-foreground` — Spartan defines only `--destructive` and hardcodes `text-white`; Yurest names a contrast color, so the pair is completed. |
|
|
160
|
+
|
|
161
|
+
To override a token, redefine it in your own `:root` *after* importing the theme.
|
|
162
|
+
|
|
163
|
+
### The `color` input
|
|
164
|
+
|
|
165
|
+
Components that carry brand color (`<yuw-button>`, `<yuw-badge>`, `<yuw-pagination>`) accept a
|
|
166
|
+
`color` input typed as `YuwColorDto`:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
type YuwColorDto =
|
|
170
|
+
| 'primary' | 'secondary' | 'destructive' | 'success'
|
|
171
|
+
| 'warning' | 'info' | 'muted' | 'violet';
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
It sets `data-yuw-color` on the host, and the theme remaps the Spartan semantic variables
|
|
175
|
+
(`--primary`, `--secondary`, `--border`, …) for that subtree — so the whole component recolors
|
|
176
|
+
consistently instead of one class being patched.
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<yuw-button color="success" variant="outline">Approve</yuw-button>
|
|
180
|
+
<yuw-badge color="warning" dot />
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Dark mode
|
|
184
|
+
|
|
185
|
+
Dark mode is supported via a `.dark` class on a root element, matching Tailwind v4's default dark
|
|
186
|
+
variant. The consuming app toggles it:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
document.documentElement.classList.toggle('dark');
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Note that `<yuw-toaster>` defaults to `theme="light"` — pass `theme="dark"` or `theme="system"`
|
|
193
|
+
explicitly in apps that render dark.
|
|
194
|
+
|
|
195
|
+
## Conventions
|
|
196
|
+
|
|
197
|
+
A few rules hold across the whole library. Knowing them removes most of the per-component surprises.
|
|
198
|
+
|
|
199
|
+
**Text is always yours.** No component hardcodes a translatable string. Anything a user reads —
|
|
200
|
+
labels, empty-state messages, accessible names for icon-only controls — is an input, often a
|
|
201
|
+
*required* one (`ariaLabel`, `previousLabel`, `emptyText`, `label`). Pass it already translated.
|
|
202
|
+
|
|
203
|
+
**Presence implies the feature.** Instead of a `removable` flag plus a `removeLabel` string, there
|
|
204
|
+
is one input: set `removeLabel` and the remove control appears, omit it and there is nothing to
|
|
205
|
+
remove. The same shape applies to `clearAriaLabel` (search input, combobox), `closeLabel` (dialog,
|
|
206
|
+
sheet) and `revealAriaLabel` (password input).
|
|
207
|
+
|
|
208
|
+
**Two-way state uses `model()`.** `[(value)]`, `[(open)]`, `[(checked)]`, `[(page)]`,
|
|
209
|
+
`[(activeTab)]` are all two-way bindable, and each also emits a `…Change` output you can listen to
|
|
210
|
+
one-way.
|
|
211
|
+
|
|
212
|
+
**Class passthrough.** Components whose host is `display: contents` accept your classes on a
|
|
213
|
+
dedicated input so they actually reach the rendered element — `class` on most components,
|
|
214
|
+
`panelClass` on overlays, `tableClass` on the datatable. They are merged **last** through
|
|
215
|
+
`tailwind-merge`, so your class always beats the component default without `!important`.
|
|
216
|
+
|
|
217
|
+
**Forms.** `<yuw-input>`, `<yuw-textarea>`, `<yuw-search-input>`, `<yuw-password-input>`,
|
|
218
|
+
`<yuw-input-otp>`, `<yuw-checkbox>`, `<yuw-switch>`, `<yuw-radio-group>`, `<yuw-combobox>` and
|
|
219
|
+
`<yuw-datepicker>` implement `ControlValueAccessor`:
|
|
220
|
+
|
|
221
|
+
```html
|
|
222
|
+
<form [formGroup]="form">
|
|
223
|
+
<label yuwLabel for="email">Email</label>
|
|
224
|
+
<yuw-input inputId="email" formControlName="email" type="email" [invalid]="emailInvalid()" />
|
|
225
|
+
|
|
226
|
+
<yuw-checkbox formControlName="terms">Accept terms</yuw-checkbox>
|
|
227
|
+
</form>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`disabled` from the forms API (`control.disable()`) and the `disabled` input are OR'd together, so
|
|
231
|
+
neither source silently overrides the other.
|
|
232
|
+
|
|
233
|
+
## Components
|
|
234
|
+
|
|
235
|
+
| Component | Selector | Import |
|
|
236
|
+
|:--------------------------------------|:----------------------------------------|:----------------------------------------------|
|
|
237
|
+
| **Actions** | | |
|
|
238
|
+
| [Button](#button) | `yuw-button` | `YuwButtonComponent` |
|
|
239
|
+
| **Form controls** | | |
|
|
240
|
+
| [Input](#input) | `yuw-input` | `YuwInputComponent` |
|
|
241
|
+
| [Textarea](#textarea) | `yuw-textarea` | `YuwTextareaComponent` |
|
|
242
|
+
| [Search input](#search-input) | `yuw-search-input` | `YuwSearchInputComponent` |
|
|
243
|
+
| [Password input](#password-input) | `yuw-password-input` | `YuwPasswordInputComponent` |
|
|
244
|
+
| [Input OTP](#input-otp) | `yuw-input-otp` | `YuwInputOtpComponent` |
|
|
245
|
+
| [Label](#label) | `label[yuwLabel]` | `YuwLabel` |
|
|
246
|
+
| [Checkbox](#checkbox) | `yuw-checkbox` | `YuwCheckboxComponent` |
|
|
247
|
+
| [Switch](#switch) | `yuw-switch` | `YuwSwitchComponent` |
|
|
248
|
+
| [Radio group](#radio-group) | `yuw-radio-group` | `YuwRadioGroupComponent` |
|
|
249
|
+
| [Combobox](#combobox) | `yuw-combobox` | `YuwComboboxComponent` |
|
|
250
|
+
| [Datepicker](#datepicker) | `yuw-datepicker` | `YuwDatepickerComponent` |
|
|
251
|
+
| **Data display** | | |
|
|
252
|
+
| [Avatar](#avatar) | `yuw-avatar` | `YuwAvatarComponent` |
|
|
253
|
+
| [Badge](#badge) | `yuw-badge` | `YuwBadgeComponent` |
|
|
254
|
+
| [Card](#card) | `[yuwCard]` | `YuwCardImports` |
|
|
255
|
+
| [Item](#item) | `[yuwItem]` | `YuwItemImports` |
|
|
256
|
+
| [Attachment](#attachment) | `[yuwAttachment]` | `YuwAttachmentDirective`, … |
|
|
257
|
+
| [Table](#table) | `[yuwTable]` | `YuwTableImports` |
|
|
258
|
+
| [Datatable](#datatable) | `yuw-datatable` | `YuwDatatableComponent` |
|
|
259
|
+
| [Empty](#empty) | `[yuwEmpty]` | `YuwEmptyImports` |
|
|
260
|
+
| [Skeleton](#skeleton) | `[yuwSkeleton]` | `YuwSkeletonDirective` |
|
|
261
|
+
| [Spinner](#spinner) | `yuw-spinner` | `YuwSpinnerComponent` |
|
|
262
|
+
| **Navigation** | | |
|
|
263
|
+
| [Accordion](#accordion) | `yuw-accordion` | `YuwAccordionImports` |
|
|
264
|
+
| [Breadcrumb](#breadcrumb) | `yuw-breadcrumb` | `YuwBreadcrumbComponent` |
|
|
265
|
+
| [Pagination](#pagination) | `yuw-pagination` | `YuwPaginationComponent` |
|
|
266
|
+
| [Tabs](#tabs) | `yuw-tabs` | `YuwTabsComponent`, `YuwTabPanelDirective` |
|
|
267
|
+
| [Sidebar](#sidebar) | `yuw-sidebar` | `YuwSidebarComponent`, … |
|
|
268
|
+
| **Overlays** | | |
|
|
269
|
+
| [Dialog](#dialog) | `yuw-dialog` | `YuwDialogImports` |
|
|
270
|
+
| [Alert dialog](#alert-dialog) | `yuw-alert-dialog` | `YuwAlertDialogComponent` |
|
|
271
|
+
| [Sheet](#sheet) | `yuw-sheet` | `YuwSheetImports` |
|
|
272
|
+
| [Popover](#popover) | `yuw-popover` | `YuwPopoverComponent` |
|
|
273
|
+
| [Tooltip](#tooltip) | `[yuwTooltip]` | `YuwTooltipDirective` |
|
|
274
|
+
| [Context menu](#context-menu) | `[yuwContextMenuTrigger]` | `YuwContextMenuImports` |
|
|
275
|
+
| **Feedback** | | |
|
|
276
|
+
| [Alert](#alert) | `yuw-alert` | `YuwAlertImports` |
|
|
277
|
+
| [Toaster](#toaster) | `yuw-toaster` | `YuwToasterComponent`, `yuwToast` |
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
### Button
|
|
282
|
+
|
|
283
|
+
Single action button, link, or a welded group of buttons.
|
|
284
|
+
|
|
285
|
+
```html
|
|
286
|
+
<yuw-button variant="outline" color="primary" (clicked)="save()">Save</yuw-button>
|
|
287
|
+
|
|
288
|
+
<yuw-button href="/dashboard" target="_blank">Dashboard</yuw-button>
|
|
289
|
+
|
|
290
|
+
<yuw-button size="icon" ariaLabel="Add item">
|
|
291
|
+
<ng-icon name="lucidePlus" />
|
|
292
|
+
</yuw-button>
|
|
293
|
+
|
|
294
|
+
<!-- Button group -->
|
|
295
|
+
<yuw-button [buttons]="actions" groupAriaLabel="Alignment" (buttonClicked)="onAction($event)" />
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### Inputs
|
|
299
|
+
|
|
300
|
+
| Input | Type | Default |
|
|
301
|
+
|:-----------------|:---------------------------------------------------------------------------------|:---------------|
|
|
302
|
+
| `variant` | `'default'|'secondary'|'outline'|'destructive'|'ghost'|'link'` | `'default'` |
|
|
303
|
+
| `size` | `'default'|'xs'|'sm'|'lg'|'icon'|'icon-xs'|'icon-sm'|'icon-lg'` | `'default'` |
|
|
304
|
+
| `color` | `YuwColorDto` | `'secondary'` |
|
|
305
|
+
| `disabled` | `boolean` | `false` |
|
|
306
|
+
| `type` | `'button'|'submit'|'reset'` | `'button'` |
|
|
307
|
+
| `href` | `string|undefined` | `undefined` |
|
|
308
|
+
| `target` | `string|undefined` | `undefined` |
|
|
309
|
+
| `transparent` | `boolean` — removes background and border | `false` |
|
|
310
|
+
| `ariaLabel` | `string|undefined` — required for icon-only buttons | `undefined` |
|
|
311
|
+
| `class` | `string` — merged onto the inner button/anchor, wins over defaults | `''` |
|
|
312
|
+
| `buttons` | `YuwButtonGroupItemDto[]|undefined` — switches to group mode | `undefined` |
|
|
313
|
+
| `orientation` | `'horizontal'|'vertical'` — group layout | `'horizontal'` |
|
|
314
|
+
| `groupAriaLabel` | `string|undefined` — accessible name of the group | `undefined` |
|
|
315
|
+
| `yuwDropdownMenuTrigger` | `TemplateRef<unknown>|undefined` | `undefined` |
|
|
316
|
+
|
|
317
|
+
#### Outputs
|
|
318
|
+
|
|
319
|
+
| Output | Payload | Description |
|
|
320
|
+
|:----------------|:------------------------|:----------------------------------------|
|
|
321
|
+
| `clicked` | `MouseEvent` | Single-button mode. |
|
|
322
|
+
| `buttonClicked` | `YuwButtonGroupClickDto`| Group mode — `{ id, event }`. |
|
|
323
|
+
|
|
324
|
+
#### Content slots
|
|
325
|
+
|
|
326
|
+
| Slot | Description |
|
|
327
|
+
|:-----------------|:-------------------------------------|
|
|
328
|
+
| `[yuwButtonIcon]`| Leading icon. |
|
|
329
|
+
| *(default)* | Button label. |
|
|
330
|
+
|
|
331
|
+
`YuwButtonGroupItemDto` entries are `{ id, label }` plus optional `variant`, `size`, `color`,
|
|
332
|
+
`disabled`, `href`, `target`, `type`, `ariaLabel`, `transparent` — each falling back to the
|
|
333
|
+
component-level input of the same name.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
### Input
|
|
338
|
+
|
|
339
|
+
Single-line text field with addon slots and form integration.
|
|
340
|
+
|
|
341
|
+
```html
|
|
342
|
+
<yuw-input [(value)]="username" placeholder="Enter username…" />
|
|
343
|
+
|
|
344
|
+
<yuw-input formControlName="email" type="email">
|
|
345
|
+
<yuw-left-addon><ng-icon name="lucideMail" /></yuw-left-addon>
|
|
346
|
+
</yuw-input>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Inputs
|
|
350
|
+
|
|
351
|
+
| Input | Type | Default |
|
|
352
|
+
|:---------------|:-------------------------------------------------|:------------|
|
|
353
|
+
| `value` | `string` — two-way | `''` |
|
|
354
|
+
| `inputId` | `string|undefined` — for external `<label for>` | `undefined` |
|
|
355
|
+
| `type` | `'text'|'email'|'tel'|'url'|'number'` | `'text'` |
|
|
356
|
+
| `inputmode` | `YuwInputModeDto|undefined` | `undefined` |
|
|
357
|
+
| `placeholder` | `string|undefined` | `undefined` |
|
|
358
|
+
| `maxlength` | `number|undefined` | `undefined` |
|
|
359
|
+
| `name` | `string|undefined` | `undefined` |
|
|
360
|
+
| `autocomplete` | `string|undefined` | `undefined` |
|
|
361
|
+
| `disabled` | `boolean` | `false` |
|
|
362
|
+
| `readonly` | `boolean` | `false` |
|
|
363
|
+
| `required` | `boolean` | `false` |
|
|
364
|
+
| `invalid` | `boolean` | `false` |
|
|
365
|
+
| `class` | `string` | `''` |
|
|
366
|
+
|
|
367
|
+
#### Outputs
|
|
368
|
+
|
|
369
|
+
| Output | Payload | Description |
|
|
370
|
+
|:------------|:---------|:------------------------------------------------|
|
|
371
|
+
| `committed` | `string` | Current value on the native `change` (blur/enter). |
|
|
372
|
+
|
|
373
|
+
#### Content slots
|
|
374
|
+
|
|
375
|
+
`yuw-left-addon`, `yuw-right-addon` — import `YuwInputAddonImports`.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### Textarea
|
|
380
|
+
|
|
381
|
+
Multi-line text field. Auto-grows where `field-sizing` is supported.
|
|
382
|
+
|
|
383
|
+
```html
|
|
384
|
+
<yuw-textarea [(value)]="bio" placeholder="Write your biography…" [rows]="4" [maxlength]="500" />
|
|
385
|
+
<yuw-textarea formControlName="comments" invalid />
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### Inputs
|
|
389
|
+
|
|
390
|
+
Same contract as [Input](#input), minus `type` / `inputmode`, plus:
|
|
391
|
+
|
|
392
|
+
| Input | Type | Default |
|
|
393
|
+
|:-------|:-------------------|:------------|
|
|
394
|
+
| `rows` | `number|undefined` | `undefined` |
|
|
395
|
+
|
|
396
|
+
#### Outputs
|
|
397
|
+
|
|
398
|
+
| Output | Payload | Description |
|
|
399
|
+
|:------------|:---------|:-------------------------------------------|
|
|
400
|
+
| `committed` | `string` | Current value on the native `change` event. |
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### Search input
|
|
405
|
+
|
|
406
|
+
Text field with a leading search icon and an optional clear button.
|
|
407
|
+
|
|
408
|
+
```html
|
|
409
|
+
<yuw-search-input
|
|
410
|
+
[(value)]="query"
|
|
411
|
+
placeholder="Search items…"
|
|
412
|
+
clearAriaLabel="Clear search"
|
|
413
|
+
(searched)="onSearch($event)"
|
|
414
|
+
/>
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### Inputs
|
|
418
|
+
|
|
419
|
+
Same contract as [Input](#input), minus `type` / `inputmode` / `maxlength`, plus:
|
|
420
|
+
|
|
421
|
+
| Input | Type | Default |
|
|
422
|
+
|:-----------------|:-------------------|:------------|
|
|
423
|
+
| `clearAriaLabel` | `string|undefined` — set it to render the clear button | `undefined` |
|
|
424
|
+
|
|
425
|
+
#### Outputs
|
|
426
|
+
|
|
427
|
+
| Output | Payload | Description |
|
|
428
|
+
|:------------|:---------|:--------------------------------------------------|
|
|
429
|
+
| `searched` | `string` | Emitted on every keystroke. |
|
|
430
|
+
| `committed` | `string` | Emitted on Enter — for search-on-submit flows. |
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
### Password input
|
|
435
|
+
|
|
436
|
+
Password field with an optional reveal toggle.
|
|
437
|
+
|
|
438
|
+
```html
|
|
439
|
+
<yuw-password-input [(value)]="password" revealAriaLabel="Toggle password visibility" />
|
|
440
|
+
<yuw-password-input formControlName="password" autocomplete="current-password" />
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
#### Inputs
|
|
444
|
+
|
|
445
|
+
Same contract as [Input](#input), minus `type` / `inputmode` / `maxlength`, plus:
|
|
446
|
+
|
|
447
|
+
| Input | Type | Default |
|
|
448
|
+
|:------------------|:----------------------------------------------------|:------------|
|
|
449
|
+
| `revealAriaLabel` | `string|undefined` — set it to render the toggle | `undefined` |
|
|
450
|
+
| `masked` | `boolean` — two-way; a parent can re-mask the value | `true` |
|
|
451
|
+
|
|
452
|
+
#### Outputs
|
|
453
|
+
|
|
454
|
+
| Output | Payload | Description |
|
|
455
|
+
|:------------|:---------|:-------------------------------------------|
|
|
456
|
+
| `committed` | `string` | Current value on the native `change` event. |
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### Input OTP
|
|
461
|
+
|
|
462
|
+
One-time password / verification code field, rendered as grouped slots.
|
|
463
|
+
|
|
464
|
+
```html
|
|
465
|
+
<yuw-input-otp [(value)]="code" [groupSizes]="[3, 3]" (completed)="verify($event)" />
|
|
466
|
+
<yuw-input-otp formControlName="otpCode" mode="numeric" />
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### Inputs
|
|
470
|
+
|
|
471
|
+
| Input | Type | Default |
|
|
472
|
+
|:-----------------|:----------------------------------------------|:------------------------|
|
|
473
|
+
| `value` | `string` — two-way | `''` |
|
|
474
|
+
| `groupSizes` | `readonly number[]` — `[3, 3]` renders `000-000` | `[6]` |
|
|
475
|
+
| `mode` | `'numeric'|'text'` | `'numeric'` |
|
|
476
|
+
| `inputId` | `string|undefined` | `undefined` |
|
|
477
|
+
| `disabled` | `boolean` | `false` |
|
|
478
|
+
| `invalid` | `boolean` | `false` |
|
|
479
|
+
| `autofocus` | `boolean` | `false` |
|
|
480
|
+
| `transformPaste` | `(pastedText: string, length: number) => string` | identity |
|
|
481
|
+
| `class` | `string` | `''` |
|
|
482
|
+
|
|
483
|
+
#### Outputs
|
|
484
|
+
|
|
485
|
+
| Output | Payload | Description |
|
|
486
|
+
|:------------|:---------|:----------------------------------------------------|
|
|
487
|
+
| `completed` | `string` | The full code, once the final slot is filled. |
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
### Label
|
|
492
|
+
|
|
493
|
+
Styled form label, applied to a native `<label>`.
|
|
494
|
+
|
|
495
|
+
```html
|
|
496
|
+
<label yuwLabel for="username">Username</label>
|
|
497
|
+
<yuw-input inputId="username" [(value)]="username" />
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Accepts the native `for` / `id` attributes.
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
### Checkbox
|
|
505
|
+
|
|
506
|
+
Projected content becomes the clickable label — the control is wrapped in a `<label>`, so clicking
|
|
507
|
+
the text toggles it and the text is announced as the accessible name.
|
|
508
|
+
|
|
509
|
+
```html
|
|
510
|
+
<yuw-checkbox [(checked)]="acceptedTerms">Accept terms</yuw-checkbox>
|
|
511
|
+
<yuw-checkbox [(indeterminate)]="isMixed" [(checked)]="allSelected">Select all</yuw-checkbox>
|
|
512
|
+
<yuw-checkbox formControlName="rememberMe" />
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### Inputs
|
|
516
|
+
|
|
517
|
+
| Input | Type | Default |
|
|
518
|
+
|:------------------|:---------------------------|:------------|
|
|
519
|
+
| `checked` | `boolean` — two-way (alias of `value`) | `false` |
|
|
520
|
+
| `indeterminate` | `boolean` — two-way | `false` |
|
|
521
|
+
| `secondary` | `boolean` — secondary fill | `false` |
|
|
522
|
+
| `disabled` | `boolean` | `false` |
|
|
523
|
+
| `required` | `boolean` | `false` |
|
|
524
|
+
| `invalid` | `boolean` | `false` |
|
|
525
|
+
| `name` | `string|undefined` | `undefined` |
|
|
526
|
+
| `inputId` | `string|undefined` | `undefined` |
|
|
527
|
+
| `ariaLabel` | `string|undefined` | `undefined` |
|
|
528
|
+
| `ariaLabelledby` | `string|undefined` | `undefined` |
|
|
529
|
+
| `ariaDescribedby` | `string|undefined` | `undefined` |
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
### Switch
|
|
534
|
+
|
|
535
|
+
Toggle for binary settings. Projected content becomes the clickable label.
|
|
536
|
+
|
|
537
|
+
```html
|
|
538
|
+
<yuw-switch [(checked)]="notificationsEnabled">Enable notifications</yuw-switch>
|
|
539
|
+
<yuw-switch formControlName="darkMode" size="sm" />
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
#### Inputs
|
|
543
|
+
|
|
544
|
+
| Input | Type | Default |
|
|
545
|
+
|:------------------|:-------------------|:------------|
|
|
546
|
+
| `checked` | `boolean` — two-way (alias of `value`) | `false` |
|
|
547
|
+
| `size` | `'default'|'sm'` | `'default'` |
|
|
548
|
+
| `disabled` | `boolean` | `false` |
|
|
549
|
+
| `inputId` | `string|undefined` | `undefined` |
|
|
550
|
+
| `ariaLabel` | `string|undefined` | `undefined` |
|
|
551
|
+
| `ariaLabelledby` | `string|undefined` | `undefined` |
|
|
552
|
+
| `ariaDescribedby` | `string|undefined` | `undefined` |
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
### Radio group
|
|
557
|
+
|
|
558
|
+
```html
|
|
559
|
+
<yuw-radio-group [options]="planOptions" [(value)]="selectedPlan" ariaLabel="Plan" />
|
|
560
|
+
<yuw-radio-group [options]="genderOptions" formControlName="gender" ariaLabelledby="gender-heading" />
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
```ts
|
|
564
|
+
interface YuwRadioOptionDto {
|
|
565
|
+
value: string;
|
|
566
|
+
label: string;
|
|
567
|
+
disabled?: boolean;
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### Inputs
|
|
572
|
+
|
|
573
|
+
| Input | Type | Default |
|
|
574
|
+
|:-----------------|:----------------------------------------------|:------------|
|
|
575
|
+
| `options` | `readonly YuwRadioOptionDto[]` — **required** | — |
|
|
576
|
+
| `value` | `string|undefined` — two-way | `undefined` |
|
|
577
|
+
| `disabled` | `boolean` — disables the whole group | `false` |
|
|
578
|
+
| `required` | `boolean` | `false` |
|
|
579
|
+
| `name` | `string|undefined` — generated when omitted | `undefined` |
|
|
580
|
+
| `ariaLabel` | `string|undefined` | `undefined` |
|
|
581
|
+
| `ariaLabelledby` | `string|undefined` | `undefined` |
|
|
582
|
+
| `class` | `string` — layout tweaks (`grid-cols-2`, …) | `''` |
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
### Combobox
|
|
587
|
+
|
|
588
|
+
Searchable select. Single or multiple selection, in-place search or a read-only trigger, with
|
|
589
|
+
optional custom option templates.
|
|
590
|
+
|
|
591
|
+
```html
|
|
592
|
+
<!-- Type-to-filter field -->
|
|
593
|
+
<yuw-combobox
|
|
594
|
+
[options]="userOptions"
|
|
595
|
+
[(value)]="selectedUser"
|
|
596
|
+
placeholder="Select user…"
|
|
597
|
+
emptyText="No user found."
|
|
598
|
+
triggerAriaLabel="Toggle options"
|
|
599
|
+
clearAriaLabel="Clear selection"
|
|
600
|
+
/>
|
|
601
|
+
|
|
602
|
+
<!-- Classic select shape -->
|
|
603
|
+
<yuw-combobox readonlyTrigger [options]="colorOptions" [(value)]="color"
|
|
604
|
+
searchPlaceholder="Search colors…" triggerAriaLabel="Toggle options" />
|
|
605
|
+
|
|
606
|
+
<!-- Multiple, with chips -->
|
|
607
|
+
<yuw-combobox multiple [options]="categoryOptions" [(value)]="categories"
|
|
608
|
+
triggerAriaLabel="Toggle options" />
|
|
609
|
+
|
|
610
|
+
<!-- Custom option template -->
|
|
611
|
+
<yuw-combobox [options]="users" [(value)]="userId" triggerAriaLabel="Toggle options">
|
|
612
|
+
<ng-template yuwComboboxItem let-option let-selected="selected">
|
|
613
|
+
<img [src]="option.data.avatar" /> {{ option.label }}
|
|
614
|
+
</ng-template>
|
|
615
|
+
</yuw-combobox>
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
```ts
|
|
619
|
+
interface YuwComboboxOptionDto<TData = unknown> {
|
|
620
|
+
value: string;
|
|
621
|
+
label: string;
|
|
622
|
+
disabled?: boolean;
|
|
623
|
+
data?: TData; // available as `option.data` in a custom item template
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
#### Inputs
|
|
628
|
+
|
|
629
|
+
| Input | Type | Default |
|
|
630
|
+
|:--------------------|:--------------------------------------------------|:------------|
|
|
631
|
+
| `options` | `YuwComboboxOptionDto<TData>[]` — **required** | — |
|
|
632
|
+
| `value` | `string|string[]|undefined` — two-way | `undefined` |
|
|
633
|
+
| `multiple` | `boolean` — chips shape; takes precedence over `readonlyTrigger` | `false` |
|
|
634
|
+
| `readonlyTrigger` | `boolean` — button trigger, search inside popover | `false` |
|
|
635
|
+
| `search` | `string` — two-way filter query | `''` |
|
|
636
|
+
| `placeholder` | `string|undefined` | `undefined` |
|
|
637
|
+
| `searchPlaceholder` | `string|undefined` | `undefined` |
|
|
638
|
+
| `emptyText` | `string|undefined` | `undefined` |
|
|
639
|
+
| `triggerAriaLabel` | `string` — **required** | — |
|
|
640
|
+
| `clearAriaLabel` | `string|undefined` — set it to render a clear button | `undefined` |
|
|
641
|
+
| `inputId` | `string|undefined` | `undefined` |
|
|
642
|
+
| `disabled` | `boolean` | `false` |
|
|
643
|
+
| `invalid` | `boolean` | `false` |
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
### Datepicker
|
|
648
|
+
|
|
649
|
+
```html
|
|
650
|
+
<yuw-datepicker [(value)]="selectedDate" placeholder="Select date…" />
|
|
651
|
+
<yuw-datepicker mode="range" [(value)]="dateRange" captionLayout="dropdown" />
|
|
652
|
+
<yuw-datepicker mode="monthYear" [(value)]="selectedMonth" />
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### Inputs
|
|
656
|
+
|
|
657
|
+
| Input | Type | Default |
|
|
658
|
+
|:----------------|:-----------------------------------------------------------------|:------------|
|
|
659
|
+
| `mode` | `'single'|'range'|'multiple'|'monthYear'` | `'single'` |
|
|
660
|
+
| `value` | `Date|[Date, Date]|Date[]|null` — two-way, shape follows `mode` | `null` |
|
|
661
|
+
| `minDate` | `Date|undefined` | `undefined` |
|
|
662
|
+
| `maxDate` | `Date|undefined` | `undefined` |
|
|
663
|
+
| `captionLayout` | `'label'|'dropdown'|'dropdown-months'|'dropdown-years'` | `'label'` |
|
|
664
|
+
| `align` | `'start'|'center'|'end'` | `'start'` |
|
|
665
|
+
| `placeholder` | `string|undefined` | `undefined` |
|
|
666
|
+
| `buttonId` | `string|undefined` — generated when omitted | `undefined` |
|
|
667
|
+
| `formatDate` | `((date: Date) => string)|undefined` | `undefined` |
|
|
668
|
+
| `disabled` | `boolean` | `false` |
|
|
669
|
+
| `invalid` | `boolean` | `false` |
|
|
670
|
+
| `class` | `string` — merged onto the trigger button | `''` |
|
|
671
|
+
|
|
672
|
+
`captionLayout` is ignored in `monthYear` mode, which renders its own month/year grid.
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
### Avatar
|
|
677
|
+
|
|
678
|
+
```html
|
|
679
|
+
<yuw-avatar src="/user.png" alt="Jane Doe" fallback="JD" />
|
|
680
|
+
<yuw-avatar alt="Jane Doe" fallback="JD" badge />
|
|
681
|
+
<yuw-avatar [group]="teamMembers" alt="Team" groupCount="+5" />
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
```ts
|
|
685
|
+
interface YuwAvatarGroupItemDto {
|
|
686
|
+
alt: string;
|
|
687
|
+
src?: string;
|
|
688
|
+
fallback: string;
|
|
689
|
+
}
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
#### Inputs
|
|
693
|
+
|
|
694
|
+
| Input | Type | Default |
|
|
695
|
+
|:-------------|:----------------------------------------|:------------|
|
|
696
|
+
| `alt` | `string` — **required** | — |
|
|
697
|
+
| `src` | `string|undefined` | `undefined` |
|
|
698
|
+
| `fallback` | `string|undefined` — initials | `undefined` |
|
|
699
|
+
| `size` | `'default'|'sm'|'lg'` | `'default'` |
|
|
700
|
+
| `badge` | `boolean` — status marker, bottom-right | `false` |
|
|
701
|
+
| `group` | `YuwAvatarGroupItemDto[]|undefined` | `undefined` |
|
|
702
|
+
| `groupCount` | `string|undefined` — overflow label | `undefined` |
|
|
703
|
+
| `class` | `string` | `''` |
|
|
704
|
+
|
|
705
|
+
#### Content slots
|
|
706
|
+
|
|
707
|
+
`[yuwAvatarBadgeIcon]` — projecting an icon turns the status dot into a role/verification marker.
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
### Badge
|
|
712
|
+
|
|
713
|
+
```html
|
|
714
|
+
<yuw-badge color="primary">New</yuw-badge>
|
|
715
|
+
<yuw-badge variant="outline" removeLabel="Remove tag" (removed)="onRemove()">Category</yuw-badge>
|
|
716
|
+
<yuw-badge dot color="success" />
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
#### Inputs
|
|
720
|
+
|
|
721
|
+
| Input | Type | Default |
|
|
722
|
+
|:--------------|:-------------------------------------------------------------------|:------------|
|
|
723
|
+
| `color` | `YuwColorDto` | `'primary'` |
|
|
724
|
+
| `variant` | `'default'|'secondary'|'destructive'|'outline'|'ghost'|'link'` | `'default'` |
|
|
725
|
+
| `dot` | `boolean` — compact dot, renders no content | `false` |
|
|
726
|
+
| `removeLabel` | `string|undefined` — set it to render the dismiss button | `undefined` |
|
|
727
|
+
|
|
728
|
+
#### Outputs
|
|
729
|
+
|
|
730
|
+
| Output | Payload | Description |
|
|
731
|
+
|:----------|:--------|:-----------------------------------|
|
|
732
|
+
| `removed` | `void` | Dismiss button activated. |
|
|
733
|
+
|
|
734
|
+
#### Content slots
|
|
735
|
+
|
|
736
|
+
`[yuwBadgeIcon]` — leading icon.
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
### Card
|
|
741
|
+
|
|
742
|
+
Directives applied to your own elements — no wrapper element is inserted.
|
|
743
|
+
|
|
744
|
+
```html
|
|
745
|
+
<div yuwCard size="sm">
|
|
746
|
+
<div yuwCardHeader>
|
|
747
|
+
<h3 yuwCardTitle>Monthly report</h3>
|
|
748
|
+
<p yuwCardDescription>Summary of the last 30 days.</p>
|
|
749
|
+
<div yuwCardAction><yuw-button size="sm" variant="ghost">Export</yuw-button></div>
|
|
750
|
+
</div>
|
|
751
|
+
<div yuwCardContent>…</div>
|
|
752
|
+
<div yuwCardFooter>…</div>
|
|
753
|
+
</div>
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
| Directive | Notes |
|
|
757
|
+
|:--------------------|:-----------------------------|
|
|
758
|
+
| `[yuwCard]` | `size`: `'default'|'sm'` |
|
|
759
|
+
| `[yuwCardHeader]` | |
|
|
760
|
+
| `[yuwCardTitle]` | |
|
|
761
|
+
| `[yuwCardDescription]` | |
|
|
762
|
+
| `[yuwCardAction]` | Top-right action area. |
|
|
763
|
+
| `[yuwCardContent]` | |
|
|
764
|
+
| `[yuwCardFooter]` | |
|
|
765
|
+
|
|
766
|
+
Import them all at once with `YuwCardImports`.
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
### Item
|
|
771
|
+
|
|
772
|
+
Row/list layout primitive.
|
|
773
|
+
|
|
774
|
+
```html
|
|
775
|
+
<div yuwItem variant="outline" size="sm">
|
|
776
|
+
<div yuwItemMedia variant="icon"><ng-icon name="lucideMail" /></div>
|
|
777
|
+
<div yuwItemContent>
|
|
778
|
+
<div yuwItemTitle>New message</div>
|
|
779
|
+
<div yuwItemDescription>You have a message from Ada Lovelace.</div>
|
|
780
|
+
</div>
|
|
781
|
+
<div yuwItemActions><yuw-button size="sm">Open</yuw-button></div>
|
|
782
|
+
</div>
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
| Directive | Notes |
|
|
786
|
+
|:-------------------------|:--------------------------------------------------|
|
|
787
|
+
| `[yuwItem]` | `variant`: `'default'|'outline'|'muted'`, `size`: `'default'|'sm'|'xs'` |
|
|
788
|
+
| `[yuwItemHeader]` | |
|
|
789
|
+
| `[yuwItemMedia]` | `variant`: `'default'|'icon'|'image'` |
|
|
790
|
+
| `[yuwItemContent]` | |
|
|
791
|
+
| `[yuwItemTitle]` | |
|
|
792
|
+
| `[yuwItemDescription]` | |
|
|
793
|
+
| `[yuwItemActions]` | |
|
|
794
|
+
| `[yuwItemFooter]` | |
|
|
795
|
+
| `[yuwItemGroup]` | |
|
|
796
|
+
| `[yuwItemSeparator]` | |
|
|
797
|
+
|
|
798
|
+
Import them all at once with `YuwItemImports`. Each directive also accepts the `yuw-item-*` element
|
|
799
|
+
form (`<yuw-item-title>`).
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
803
|
+
### Attachment
|
|
804
|
+
|
|
805
|
+
File attachment card, with upload states.
|
|
806
|
+
|
|
807
|
+
```html
|
|
808
|
+
<div yuwAttachment state="uploading" size="sm">
|
|
809
|
+
<div yuwAttachmentMedia variant="icon"><ng-icon name="lucideFileText" /></div>
|
|
810
|
+
<div yuwAttachmentContent>
|
|
811
|
+
<span yuwAttachmentTitle>report.pdf</span>
|
|
812
|
+
<span yuwAttachmentDescription>2.4 MB</span>
|
|
813
|
+
</div>
|
|
814
|
+
<div yuwAttachmentActions>
|
|
815
|
+
<button yuwAttachmentAction><ng-icon name="lucideX" /></button>
|
|
816
|
+
</div>
|
|
817
|
+
</div>
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
| Directive | Notes |
|
|
821
|
+
|:------------------------------|:----------------------------------------------------------------------|
|
|
822
|
+
| `[yuwAttachment]` | `state`: `'idle'|'uploading'|'processing'|'error'|'done'`, `size`: `'default'|'sm'|'xs'`, `orientation`: `'horizontal'|'vertical'` |
|
|
823
|
+
| `[yuwAttachmentGroup]` | |
|
|
824
|
+
| `[yuwAttachmentMedia]` | `variant`: `'icon'|'image'` |
|
|
825
|
+
| `[yuwAttachmentContent]` | |
|
|
826
|
+
| `[yuwAttachmentTitle]` | |
|
|
827
|
+
| `[yuwAttachmentDescription]` | |
|
|
828
|
+
| `[yuwAttachmentActions]` | |
|
|
829
|
+
| `button[yuwAttachmentAction]` | Action button inside the card. |
|
|
830
|
+
| `[yuwAttachmentTrigger]` | Makes a `<button>` / `<a>` the card's primary trigger. |
|
|
831
|
+
|
|
832
|
+
---
|
|
833
|
+
|
|
834
|
+
### Table
|
|
835
|
+
|
|
836
|
+
Styling directives for a table you write yourself.
|
|
837
|
+
|
|
838
|
+
```html
|
|
839
|
+
<div yuwTableContainer>
|
|
840
|
+
<table yuwTable>
|
|
841
|
+
<caption yuwCaption>Team members and their roles.</caption>
|
|
842
|
+
<thead yuwTHead>
|
|
843
|
+
<tr yuwTr><th yuwTh>Name</th><th yuwTh>Role</th></tr>
|
|
844
|
+
</thead>
|
|
845
|
+
<tbody yuwTBody>
|
|
846
|
+
<tr yuwTr><td yuwTd>Ada Lovelace</td><td yuwTd>Engineer</td></tr>
|
|
847
|
+
</tbody>
|
|
848
|
+
<tfoot yuwTFoot>…</tfoot>
|
|
849
|
+
</table>
|
|
850
|
+
</div>
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
Import them all at once with `YuwTableImports`.
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
### Datatable
|
|
858
|
+
|
|
859
|
+
Sorting, pagination, row selection, column visibility and a loading skeleton, over
|
|
860
|
+
[TanStack Table](https://tanstack.com/table).
|
|
861
|
+
|
|
862
|
+
```html
|
|
863
|
+
<yuw-datatable
|
|
864
|
+
[columns]="columns"
|
|
865
|
+
[data]="users"
|
|
866
|
+
sortable
|
|
867
|
+
paginated
|
|
868
|
+
selectable
|
|
869
|
+
[loading]="loading()"
|
|
870
|
+
[(columnVisibility)]="columnVisibility"
|
|
871
|
+
emptyText="No users found."
|
|
872
|
+
previousPageLabel="Previous page"
|
|
873
|
+
nextPageLabel="Next page"
|
|
874
|
+
(selectedRowsChange)="onSelect($event)"
|
|
875
|
+
/>
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
#### Inputs
|
|
879
|
+
|
|
880
|
+
| Input | Type | Default |
|
|
881
|
+
|:--------------------|:----------------------------------------------|:-------------------------------|
|
|
882
|
+
| `columns` | `YuwDatatableColumnDef<TData>[]` | `[]` |
|
|
883
|
+
| `data` | `TData[]` | `[]` |
|
|
884
|
+
| `sortable` | `boolean` | `false` |
|
|
885
|
+
| `paginated` | `boolean` | `false` |
|
|
886
|
+
| `selectable` | `boolean` | `false` |
|
|
887
|
+
| `loading` | `boolean` — renders skeleton rows | `false` |
|
|
888
|
+
| `loadingRows` | `number` | `5` |
|
|
889
|
+
| `emptyText` | `string|undefined` | `undefined` |
|
|
890
|
+
| `previousPageLabel` | `string` — **required** | — |
|
|
891
|
+
| `nextPageLabel` | `string` — **required** | — |
|
|
892
|
+
| `caption` | `string|undefined` | `undefined` |
|
|
893
|
+
| `tableClass` | `string|undefined` — merged onto `<table>` | `undefined` |
|
|
894
|
+
| `sorting` | `SortingState` — two-way | `[]` |
|
|
895
|
+
| `columnFilters` | `ColumnFiltersState` — two-way | `[]` |
|
|
896
|
+
| `columnVisibility` | `ColumnVisibilityState` — two-way | `{}` |
|
|
897
|
+
| `rowSelection` | `RowSelectionState` — two-way | `{}` |
|
|
898
|
+
| `pagination` | `PaginationState` — two-way | `{ pageIndex: 0, pageSize: 10 }` |
|
|
899
|
+
|
|
900
|
+
#### Outputs
|
|
901
|
+
|
|
902
|
+
| Output | Payload | Description |
|
|
903
|
+
|:---------------------|:----------|:----------------------------------------------------------------|
|
|
904
|
+
| `selectedRowsChange` | `TData[]` | Selection changes. The initial state does not emit. |
|
|
905
|
+
|
|
906
|
+
> `selectable` enables the selection *state*; the checkbox column itself is a display column you
|
|
907
|
+
> provide (`id: 'select'`, with `flexRenderComponent(...)` header/cell calling TanStack's toggle
|
|
908
|
+
> handlers).
|
|
909
|
+
|
|
910
|
+
---
|
|
911
|
+
|
|
912
|
+
### Empty
|
|
913
|
+
|
|
914
|
+
Empty-state panel ("no results", "inbox empty").
|
|
915
|
+
|
|
916
|
+
```html
|
|
917
|
+
<div yuwEmpty>
|
|
918
|
+
<div yuwEmptyHeader>
|
|
919
|
+
<div yuwEmptyMedia variant="icon"><ng-icon name="lucideFolderOpen" /></div>
|
|
920
|
+
<h3 yuwEmptyTitle>No files found</h3>
|
|
921
|
+
<p yuwEmptyDescription>Try uploading a file or changing your query.</p>
|
|
922
|
+
</div>
|
|
923
|
+
<div yuwEmptyContent>
|
|
924
|
+
<yuw-button>Upload file</yuw-button>
|
|
925
|
+
</div>
|
|
926
|
+
</div>
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
`[yuwEmptyMedia]` accepts `variant`: `'default'|'icon'`. Import them all at once with
|
|
930
|
+
`YuwEmptyImports`.
|
|
931
|
+
|
|
932
|
+
---
|
|
933
|
+
|
|
934
|
+
### Skeleton
|
|
935
|
+
|
|
936
|
+
```html
|
|
937
|
+
<div yuwSkeleton class="h-4 w-32 rounded"></div>
|
|
938
|
+
<div yuwSkeleton class="size-10 rounded-full"></div>
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
Sized with standard CSS height/width classes on the host element.
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
|
|
945
|
+
### Spinner
|
|
946
|
+
|
|
947
|
+
```html
|
|
948
|
+
<yuw-spinner label="Loading" />
|
|
949
|
+
<yuw-spinner label="Refreshing" icon="lucideRefreshCw" />
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
#### Inputs
|
|
953
|
+
|
|
954
|
+
| Input | Type | Default |
|
|
955
|
+
|:--------|:---------|:-------------------|
|
|
956
|
+
| `label` | `string` — **required**, the accessible name | — |
|
|
957
|
+
| `icon` | `string` — any registered icon name | `'lucideLoader2'` |
|
|
958
|
+
|
|
959
|
+
The spinner inherits its size from the container's font size — wrap it in `text-2xl` to scale it.
|
|
960
|
+
|
|
961
|
+
---
|
|
962
|
+
|
|
963
|
+
### Accordion
|
|
964
|
+
|
|
965
|
+
```html
|
|
966
|
+
<yuw-accordion type="multiple">
|
|
967
|
+
<yuw-accordion-item [disabled]="false" (openedChange)="onToggle($event)">
|
|
968
|
+
<yuw-accordion-trigger>Shipping</yuw-accordion-trigger>
|
|
969
|
+
<yuw-accordion-content>Delivered in 24–48 h.</yuw-accordion-content>
|
|
970
|
+
</yuw-accordion-item>
|
|
971
|
+
</yuw-accordion>
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
| Element | Inputs / Outputs |
|
|
975
|
+
|:--------------------------|:----------------------------------------------------------------------|
|
|
976
|
+
| `yuw-accordion` | `type`: `'single'|'multiple'` (default `'single'`), `orientation`: `'vertical'|'horizontal'` (default `'vertical'`) |
|
|
977
|
+
| `yuw-accordion-item` | `isOpened`: `boolean`, `disabled`: `boolean`; output `openedChange` |
|
|
978
|
+
| `yuw-accordion-trigger` | `triggerClass`: `string` — merged after defaults, so it wins |
|
|
979
|
+
| `yuw-accordion-content` | — |
|
|
980
|
+
|
|
981
|
+
Import them all at once with `YuwAccordionImports`.
|
|
982
|
+
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
### Breadcrumb
|
|
986
|
+
|
|
987
|
+
```html
|
|
988
|
+
<yuw-breadcrumb
|
|
989
|
+
[items]="[{ label: 'Home', href: '/' }, { label: 'Settings' }]"
|
|
990
|
+
ariaLabel="Breadcrumb"
|
|
991
|
+
/>
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
```ts
|
|
995
|
+
interface YuwBreadcrumbItemDto {
|
|
996
|
+
label: string;
|
|
997
|
+
href?: string;
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
#### Inputs
|
|
1002
|
+
|
|
1003
|
+
| Input | Type | Default |
|
|
1004
|
+
|:------------|:------------------------------------|:--------|
|
|
1005
|
+
| `items` | `YuwBreadcrumbItemDto[]` — **required** | — |
|
|
1006
|
+
| `ariaLabel` | `string` — **required** | — |
|
|
1007
|
+
| `separator` | `string` | `'/'` |
|
|
1008
|
+
|
|
1009
|
+
The last item is announced as the current page (`aria-current="page"`); intermediate items render
|
|
1010
|
+
as links when they have an `href`.
|
|
1011
|
+
|
|
1012
|
+
---
|
|
1013
|
+
|
|
1014
|
+
### Pagination
|
|
1015
|
+
|
|
1016
|
+
```html
|
|
1017
|
+
<yuw-pagination
|
|
1018
|
+
[(page)]="currentPage"
|
|
1019
|
+
[totalPages]="20"
|
|
1020
|
+
previousLabel="Previous page"
|
|
1021
|
+
nextLabel="Next page"
|
|
1022
|
+
ellipsisSrText="More pages"
|
|
1023
|
+
ariaLabel="Pagination"
|
|
1024
|
+
/>
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
#### Inputs
|
|
1028
|
+
|
|
1029
|
+
| Input | Type | Default |
|
|
1030
|
+
|:-----------------|:-----------------------------------------------------------------------|:------------|
|
|
1031
|
+
| `page` | `number` — two-way, **required** | — |
|
|
1032
|
+
| `totalPages` | `number` — **required** | — |
|
|
1033
|
+
| `previousLabel` | `string` — **required** | — |
|
|
1034
|
+
| `nextLabel` | `string` — **required** | — |
|
|
1035
|
+
| `ellipsisSrText` | `string` — **required** | — |
|
|
1036
|
+
| `ariaLabel` | `string` — **required** | — |
|
|
1037
|
+
| `size` | `'default'|'xs'|'sm'|'lg'|'icon'|'icon-xs'|'icon-sm'|'icon-lg'` | `'icon'` |
|
|
1038
|
+
| `color` | `YuwColorDto` | `'primary'` |
|
|
1039
|
+
|
|
1040
|
+
`getPaginationRange(page, totalPages)` is exported if you need the same page/ellipsis sequence
|
|
1041
|
+
elsewhere.
|
|
1042
|
+
|
|
1043
|
+
---
|
|
1044
|
+
|
|
1045
|
+
### Tabs
|
|
1046
|
+
|
|
1047
|
+
Triggers come from the `tabs` input; each panel is an `<ng-template yuwTabPanel="id">` whose id
|
|
1048
|
+
matches a tab. Panels are lazy — instantiated the first time their tab becomes active.
|
|
1049
|
+
|
|
1050
|
+
```html
|
|
1051
|
+
<yuw-tabs [tabs]="settingsTabs" [(activeTab)]="selected" variant="line">
|
|
1052
|
+
<ng-template yuwTabPanel="general">Workspace name, timezone and locale.</ng-template>
|
|
1053
|
+
<ng-template yuwTabPanel="billing">Plan, invoices and payment method.</ng-template>
|
|
1054
|
+
</yuw-tabs>
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
```ts
|
|
1058
|
+
interface YuwTabItemDto {
|
|
1059
|
+
id: string;
|
|
1060
|
+
label: string;
|
|
1061
|
+
disabled?: boolean;
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
#### Inputs
|
|
1066
|
+
|
|
1067
|
+
| Input | Type | Default |
|
|
1068
|
+
|:-----------------|:--------------------------------|:---------------|
|
|
1069
|
+
| `tabs` | `YuwTabItemDto[]` — **required**| — |
|
|
1070
|
+
| `activeTab` | `string` — two-way, **required**| — |
|
|
1071
|
+
| `variant` | `'default'|'line'` | `'default'` |
|
|
1072
|
+
| `orientation` | `'horizontal'|'vertical'` | `'horizontal'` |
|
|
1073
|
+
| `activationMode` | `'automatic'|'manual'` | `'automatic'` |
|
|
1074
|
+
|
|
1075
|
+
---
|
|
1076
|
+
|
|
1077
|
+
### Sidebar
|
|
1078
|
+
|
|
1079
|
+
Collapsible navigation sidebar — a fixed panel on desktop, a slide-in sheet on mobile. Open state
|
|
1080
|
+
lives in `YuwSidebarService`, so `<yuw-sidebar-trigger>` works from anywhere on the page.
|
|
1081
|
+
|
|
1082
|
+
```html
|
|
1083
|
+
<div yuwSidebarWrapper>
|
|
1084
|
+
<yuw-sidebar collapsible="icon">
|
|
1085
|
+
<div yuwSidebarHeader>Yurest</div>
|
|
1086
|
+
|
|
1087
|
+
<div yuwSidebarContent>
|
|
1088
|
+
<div yuwSidebarGroup>
|
|
1089
|
+
<div yuwSidebarGroupLabel>Management</div>
|
|
1090
|
+
<div yuwSidebarGroupContent>
|
|
1091
|
+
<ul yuwSidebarMenu>
|
|
1092
|
+
<li yuwSidebarMenuItem>
|
|
1093
|
+
<a yuwSidebarMenuButton [isActive]="true" tooltip="Orders">
|
|
1094
|
+
<ng-icon name="lucideShoppingCart" />
|
|
1095
|
+
<span>Orders</span>
|
|
1096
|
+
</a>
|
|
1097
|
+
<span yuwSidebarMenuBadge>12</span>
|
|
1098
|
+
</li>
|
|
1099
|
+
</ul>
|
|
1100
|
+
</div>
|
|
1101
|
+
</div>
|
|
1102
|
+
</div>
|
|
1103
|
+
|
|
1104
|
+
<div yuwSidebarFooter>…</div>
|
|
1105
|
+
</yuw-sidebar>
|
|
1106
|
+
|
|
1107
|
+
<main yuwSidebarInset>
|
|
1108
|
+
<yuw-sidebar-trigger label="Toggle sidebar" />
|
|
1109
|
+
</main>
|
|
1110
|
+
</div>
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
#### `<yuw-sidebar>` inputs
|
|
1114
|
+
|
|
1115
|
+
| Input | Type | Default |
|
|
1116
|
+
|:------------------------|:------------------------------------------|:---------------|
|
|
1117
|
+
| `side` | `'left'|'right'` | `'left'` |
|
|
1118
|
+
| `variant` | `'sidebar'|'floating'|'inset'` | `'sidebar'` |
|
|
1119
|
+
| `collapsible` | `'offcanvas'|'icon'|'none'` | `'offcanvas'` |
|
|
1120
|
+
| `sidebarWidthMobile` | `string` — any CSS length | `'18rem'` |
|
|
1121
|
+
| `sidebarContainerClass` | `string` — merged onto the desktop container | `''` |
|
|
1122
|
+
|
|
1123
|
+
#### Structure directives
|
|
1124
|
+
|
|
1125
|
+
| Directive | Notes |
|
|
1126
|
+
|:-------------------------------------|:------------------------------------------------------------------|
|
|
1127
|
+
| `[yuwSidebarWrapper]` | `sidebarWidth`, `sidebarWidthIcon` |
|
|
1128
|
+
| `[yuwSidebarHeader]` / `[yuwSidebarContent]` / `[yuwSidebarFooter]` | |
|
|
1129
|
+
| `[yuwSidebarGroup]` / `[yuwSidebarGroupLabel]` / `[yuwSidebarGroupContent]` | |
|
|
1130
|
+
| `ul[yuwSidebarMenu]` / `li[yuwSidebarMenuItem]` | |
|
|
1131
|
+
| `a[yuwSidebarMenuButton]`, `button[…]` | `variant`: `'default'|'outline'`, `size`: `'default'|'sm'|'lg'`, `isActive`, `closeMobileSidebarOnClick`; add Spartan's `tooltip` to label items while collapsed to icons |
|
|
1132
|
+
| `[yuwSidebarMenuBadge]` | Trailing count/status. |
|
|
1133
|
+
| `ul[yuwSidebarMenuSub]` / `li[yuwSidebarMenuSubItem]` / `a[yuwSidebarMenuSubButton]` | Nested level. |
|
|
1134
|
+
| `[yuwSidebarSeparator]` | |
|
|
1135
|
+
| `button[yuwSidebarRail]` | `label` — **required**, thin edge toggle. |
|
|
1136
|
+
| `main[yuwSidebarInset]` | Main content area. |
|
|
1137
|
+
| `<yuw-sidebar-trigger>` | `label` — **required**, screen-reader-only. |
|
|
1138
|
+
|
|
1139
|
+
Inject `YuwSidebarService` to read or drive the state (`state()`, `isMobile()`, `openMobile()`,
|
|
1140
|
+
`toggle()`); configure defaults app-wide with `provideYuwSidebarConfig({ … })`.
|
|
1141
|
+
|
|
1142
|
+
---
|
|
1143
|
+
|
|
1144
|
+
### Dialog
|
|
1145
|
+
|
|
1146
|
+
Modal overlay for focused tasks and forms. The body scrolls internally when taller than the
|
|
1147
|
+
viewport.
|
|
1148
|
+
|
|
1149
|
+
> Provide either `title` or `ariaLabel` — a modal without an accessible name is announced as an
|
|
1150
|
+
> anonymous dialog by screen readers.
|
|
1151
|
+
|
|
1152
|
+
```html
|
|
1153
|
+
<yuw-dialog [(open)]="isOpen" title="Create project"
|
|
1154
|
+
description="Give it a name to get started." closeLabel="Close">
|
|
1155
|
+
<ng-container yuwDialogTrigger>Create project</ng-container>
|
|
1156
|
+
|
|
1157
|
+
<yuw-input [(value)]="name" placeholder="Project name" />
|
|
1158
|
+
|
|
1159
|
+
<div yuwDialogFooter>
|
|
1160
|
+
<yuw-button (clicked)="save()">Save</yuw-button>
|
|
1161
|
+
</div>
|
|
1162
|
+
</yuw-dialog>
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
#### Inputs
|
|
1166
|
+
|
|
1167
|
+
| Input | Type | Default |
|
|
1168
|
+
|:-----------------|:---------------------------------|:------------|
|
|
1169
|
+
| `open` | `boolean` — two-way | `false` |
|
|
1170
|
+
| `showTrigger` | `boolean` — set `false` when driving via `[(open)]` only | `true` |
|
|
1171
|
+
| `title` | `string|undefined` | `undefined` |
|
|
1172
|
+
| `description` | `string|undefined` | `undefined` |
|
|
1173
|
+
| `ariaLabel` | `string|undefined` | `undefined` |
|
|
1174
|
+
| `closeLabel` | `string|undefined` — set it to render the corner ✕ | `undefined` |
|
|
1175
|
+
| `panelClass` | `string|undefined` — e.g. `sm:max-w-lg` | `undefined` |
|
|
1176
|
+
| `triggerVariant` | button variant | `'outline'` |
|
|
1177
|
+
| `triggerSize` | button size | `'default'` |
|
|
1178
|
+
|
|
1179
|
+
#### Content slots
|
|
1180
|
+
|
|
1181
|
+
`[yuwDialogTrigger]`, `[yuwDialogFooter]` (the footer renders only when filled), and the default
|
|
1182
|
+
slot for the body. Import with `YuwDialogImports`.
|
|
1183
|
+
|
|
1184
|
+
---
|
|
1185
|
+
|
|
1186
|
+
### Alert dialog
|
|
1187
|
+
|
|
1188
|
+
Blocking confirmation for destructive or irreversible actions. Unlike `<yuw-dialog>` it cannot be
|
|
1189
|
+
dismissed by clicking the backdrop.
|
|
1190
|
+
|
|
1191
|
+
```html
|
|
1192
|
+
<yuw-alert-dialog
|
|
1193
|
+
[(open)]="isOpen"
|
|
1194
|
+
title="Delete invoice?"
|
|
1195
|
+
description="This action cannot be undone."
|
|
1196
|
+
confirmLabel="Delete"
|
|
1197
|
+
cancelLabel="Cancel"
|
|
1198
|
+
confirmVariant="destructive"
|
|
1199
|
+
(confirmed)="delete()"
|
|
1200
|
+
/>
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
#### Inputs
|
|
1204
|
+
|
|
1205
|
+
| Input | Type | Default |
|
|
1206
|
+
|:-----------------|:--------------------|:------------|
|
|
1207
|
+
| `open` | `boolean` — two-way | `false` |
|
|
1208
|
+
| `showTrigger` | `boolean` | `true` |
|
|
1209
|
+
| `title` | `string` — **required** | — |
|
|
1210
|
+
| `confirmLabel` | `string` — **required** | — |
|
|
1211
|
+
| `cancelLabel` | `string` — **required** | — |
|
|
1212
|
+
| `description` | `string|undefined` | `undefined` |
|
|
1213
|
+
| `confirmVariant` | button variant | `'default'` |
|
|
1214
|
+
| `size` | `'default'|'sm'` | `'default'` |
|
|
1215
|
+
| `triggerVariant` | button variant | `'outline'` |
|
|
1216
|
+
| `triggerSize` | button size | `'default'` |
|
|
1217
|
+
|
|
1218
|
+
#### Outputs
|
|
1219
|
+
|
|
1220
|
+
| Output | Payload | Description |
|
|
1221
|
+
|:------------|:--------|:--------------------------------------------------------------------------|
|
|
1222
|
+
| `confirmed` | `void` | Confirm action activated. |
|
|
1223
|
+
| `cancelled` | `void` | Cancel **button** activated — programmatic closes do not emit it. |
|
|
1224
|
+
|
|
1225
|
+
#### Content slots
|
|
1226
|
+
|
|
1227
|
+
`[yuwAlertDialogTrigger]`, `[yuwAlertDialogMedia]`.
|
|
1228
|
+
|
|
1229
|
+
---
|
|
1230
|
+
|
|
1231
|
+
### Sheet
|
|
1232
|
+
|
|
1233
|
+
Slide-in panel for side drawers and detail views. Same accessible-name rule as
|
|
1234
|
+
[Dialog](#dialog).
|
|
1235
|
+
|
|
1236
|
+
```html
|
|
1237
|
+
<yuw-sheet [(open)]="isOpen" side="right" title="Edit profile"
|
|
1238
|
+
description="Update your account details." closeLabel="Close">
|
|
1239
|
+
<ng-container yuwSheetTrigger>Edit profile</ng-container>
|
|
1240
|
+
|
|
1241
|
+
<p>Sheet form content goes here.</p>
|
|
1242
|
+
|
|
1243
|
+
<div yuwSheetFooter>
|
|
1244
|
+
<yuw-button (clicked)="save()">Save changes</yuw-button>
|
|
1245
|
+
</div>
|
|
1246
|
+
</yuw-sheet>
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
#### Inputs
|
|
1250
|
+
|
|
1251
|
+
Same as [Dialog](#dialog), plus:
|
|
1252
|
+
|
|
1253
|
+
| Input | Type | Default |
|
|
1254
|
+
|:-------|:----------------------------------|:----------|
|
|
1255
|
+
| `side` | `'top'|'bottom'|'left'|'right'` | `'right'` |
|
|
1256
|
+
|
|
1257
|
+
#### Content slots
|
|
1258
|
+
|
|
1259
|
+
`[yuwSheetTrigger]`, `[yuwSheetFooter]`. Import with `YuwSheetImports`.
|
|
1260
|
+
|
|
1261
|
+
---
|
|
1262
|
+
|
|
1263
|
+
### Popover
|
|
1264
|
+
|
|
1265
|
+
```html
|
|
1266
|
+
<yuw-popover [(open)]="isOpen" align="start" title="Notifications"
|
|
1267
|
+
description="You're all caught up.">
|
|
1268
|
+
<button yuwPopoverTrigger>View notifications</button>
|
|
1269
|
+
|
|
1270
|
+
<p>No new notifications since your last visit.</p>
|
|
1271
|
+
</yuw-popover>
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
#### Inputs
|
|
1275
|
+
|
|
1276
|
+
| Input | Type | Default |
|
|
1277
|
+
|:-----------------|:---------------------------|:-----------|
|
|
1278
|
+
| `open` | `boolean` — two-way | `false` |
|
|
1279
|
+
| `showTrigger` | `boolean` | `true` |
|
|
1280
|
+
| `align` | `'start'|'center'|'end'` | `'center'` |
|
|
1281
|
+
| `sideOffset` | `number` — px | `4` |
|
|
1282
|
+
| `title` | `string|undefined` | `undefined`|
|
|
1283
|
+
| `description` | `string|undefined` | `undefined`|
|
|
1284
|
+
| `panelClass` | `string|undefined` — e.g. `w-80` | `undefined` |
|
|
1285
|
+
| `triggerVariant` | button variant | `'outline'`|
|
|
1286
|
+
| `triggerSize` | button size | `'default'`|
|
|
1287
|
+
|
|
1288
|
+
#### Content slots
|
|
1289
|
+
|
|
1290
|
+
`[yuwPopoverTrigger]`, plus the default slot for the panel body.
|
|
1291
|
+
|
|
1292
|
+
---
|
|
1293
|
+
|
|
1294
|
+
### Tooltip
|
|
1295
|
+
|
|
1296
|
+
Applied directly to the trigger element — no wrapper markup.
|
|
1297
|
+
|
|
1298
|
+
```html
|
|
1299
|
+
<yuw-button yuwTooltip="Save your changes">Save</yuw-button>
|
|
1300
|
+
<yuw-button [yuwTooltip]="helpText" position="right" [showDelay]="500">Help</yuw-button>
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
#### Inputs
|
|
1304
|
+
|
|
1305
|
+
| Input | Type | Default |
|
|
1306
|
+
|:------------------|:----------------------------------------|:--------|
|
|
1307
|
+
| `yuwTooltip` | `string|TemplateRef` — the content | — |
|
|
1308
|
+
| `position` | `'top'|'bottom'|'left'|'right'` | `'top'` |
|
|
1309
|
+
| `showDelay` | `number` — ms | `150` |
|
|
1310
|
+
| `hideDelay` | `number` — ms | `100` |
|
|
1311
|
+
| `tooltipDisabled` | `boolean` | `false` |
|
|
1312
|
+
|
|
1313
|
+
---
|
|
1314
|
+
|
|
1315
|
+
### Context menu
|
|
1316
|
+
|
|
1317
|
+
Right-click menu, declared as a template and attached to any element.
|
|
1318
|
+
|
|
1319
|
+
```html
|
|
1320
|
+
<div [yuwContextMenuTrigger]="menu">Right-click me</div>
|
|
1321
|
+
|
|
1322
|
+
<ng-template #menu>
|
|
1323
|
+
<div yuwContextMenu>
|
|
1324
|
+
<div yuwContextMenuLabel>Actions</div>
|
|
1325
|
+
|
|
1326
|
+
<button yuwContextMenuItem (triggered)="edit()">
|
|
1327
|
+
Edit <span yuwContextMenuShortcut>⌘E</span>
|
|
1328
|
+
</button>
|
|
1329
|
+
|
|
1330
|
+
<div yuwContextMenuSeparator></div>
|
|
1331
|
+
|
|
1332
|
+
<div yuwContextMenuGroup>
|
|
1333
|
+
<button yuwContextMenuRadio [checked]="order() === 'asc'" (triggered)="setOrder('asc')">
|
|
1334
|
+
Ascending
|
|
1335
|
+
<yuw-context-menu-radio-indicator />
|
|
1336
|
+
</button>
|
|
1337
|
+
</div>
|
|
1338
|
+
|
|
1339
|
+
<button yuwContextMenuCheckbox [checked]="showArchived()" (triggered)="toggleArchived()">
|
|
1340
|
+
Show archived
|
|
1341
|
+
<yuw-context-menu-checkbox-indicator />
|
|
1342
|
+
</button>
|
|
1343
|
+
|
|
1344
|
+
<button [yuwContextMenuSubTrigger]="subMenu">
|
|
1345
|
+
More tools
|
|
1346
|
+
<yuw-context-menu-sub-indicator />
|
|
1347
|
+
</button>
|
|
1348
|
+
</div>
|
|
1349
|
+
</ng-template>
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
| Directive | Inputs / Outputs |
|
|
1353
|
+
|:----------------------------|:----------------------------------------------------------------|
|
|
1354
|
+
| `[yuwContextMenuTrigger]` | Menu `TemplateRef`; `yuwContextMenuTriggerData`; outputs `opened`, `closed` |
|
|
1355
|
+
| `[yuwContextMenu]` | Menu panel. |
|
|
1356
|
+
| `[yuwContextMenuItem]` | Output `triggered`. |
|
|
1357
|
+
| `[yuwContextMenuCheckbox]` | `checked`, `disabled`; output `triggered`. |
|
|
1358
|
+
| `[yuwContextMenuRadio]` | `checked`, `disabled`; output `triggered`. |
|
|
1359
|
+
| `[yuwContextMenuGroup]` / `[yuwContextMenuLabel]` / `[yuwContextMenuSeparator]` / `[yuwContextMenuShortcut]` | Structure. |
|
|
1360
|
+
| `[yuwContextMenuSub]` / `[yuwContextMenuSubTrigger]` | Nested menus. |
|
|
1361
|
+
| `<yuw-context-menu-checkbox-indicator>` / `…-radio-indicator>` / `…-sub-indicator>` | Indicators. |
|
|
1362
|
+
|
|
1363
|
+
Checkbox and radio items keep the menu open; drive their `checked` state from `triggered`. Import
|
|
1364
|
+
them all at once with `YuwContextMenuImports`.
|
|
1365
|
+
|
|
1366
|
+
---
|
|
1367
|
+
|
|
1368
|
+
### Alert
|
|
1369
|
+
|
|
1370
|
+
Inline, non-blocking message panel.
|
|
1371
|
+
|
|
1372
|
+
```html
|
|
1373
|
+
<yuw-alert variant="destructive" title="Payment declined"
|
|
1374
|
+
description="Check the card details and try again.">
|
|
1375
|
+
<ng-icon yuwAlertIcon name="lucideTriangleAlert" />
|
|
1376
|
+
<yuw-button yuwAlertAction size="sm" variant="ghost">Retry</yuw-button>
|
|
1377
|
+
</yuw-alert>
|
|
1378
|
+
|
|
1379
|
+
<!-- Rich content replaces the plain-text inputs -->
|
|
1380
|
+
<yuw-alert>
|
|
1381
|
+
<span yuwAlertTitle>Terms <strong>updated</strong></span>
|
|
1382
|
+
<span yuwAlertDescription>Review the <a href="/changes">changes</a> before continuing.</span>
|
|
1383
|
+
</yuw-alert>
|
|
1384
|
+
```
|
|
1385
|
+
|
|
1386
|
+
#### Inputs
|
|
1387
|
+
|
|
1388
|
+
| Input | Type | Default |
|
|
1389
|
+
|:--------------|:----------------------------|:------------|
|
|
1390
|
+
| `variant` | `'default'|'destructive'` | `'default'` |
|
|
1391
|
+
| `title` | `string|undefined` | `undefined` |
|
|
1392
|
+
| `description` | `string|undefined` | `undefined` |
|
|
1393
|
+
| `class` | `string` | `''` |
|
|
1394
|
+
|
|
1395
|
+
#### Content slots
|
|
1396
|
+
|
|
1397
|
+
`[yuwAlertIcon]`, `[yuwAlertTitle]`, `[yuwAlertDescription]`, `[yuwAlertAction]`. A projected title
|
|
1398
|
+
or description replaces the corresponding input. Import with `YuwAlertImports`.
|
|
1399
|
+
|
|
1400
|
+
---
|
|
1401
|
+
|
|
1402
|
+
### Toaster
|
|
1403
|
+
|
|
1404
|
+
Mount `<yuw-toaster />` **once** near the app root, then dispatch toasts from anywhere with
|
|
1405
|
+
`yuwToast`.
|
|
1406
|
+
|
|
1407
|
+
```html
|
|
1408
|
+
<yuw-toaster position="top-right" theme="system" closeButton />
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
```ts
|
|
1412
|
+
import { yuwToast } from 'yukit-web';
|
|
1413
|
+
|
|
1414
|
+
yuwToast('Settings saved');
|
|
1415
|
+
yuwToast.success('Invoice sent', { description: 'A copy was emailed to the customer.' });
|
|
1416
|
+
yuwToast.error('Payment declined');
|
|
1417
|
+
yuwToast.warning('Storage almost full');
|
|
1418
|
+
yuwToast.info('Maintenance on Sunday');
|
|
1419
|
+
|
|
1420
|
+
yuwToast.promise(saveSettings(), {
|
|
1421
|
+
loading: 'Saving…',
|
|
1422
|
+
success: 'Saved',
|
|
1423
|
+
error: 'Could not save',
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
yuwToast('Item deleted', {
|
|
1427
|
+
action: { label: 'Undo', onClick: () => restore() },
|
|
1428
|
+
});
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
#### Inputs
|
|
1432
|
+
|
|
1433
|
+
| Input | Type | Default |
|
|
1434
|
+
|:----------------|:-----------------------------------------------------------------------------------|:-----------------|
|
|
1435
|
+
| `position` | `'top-left'|'top-center'|'top-right'|'bottom-left'|'bottom-center'|'bottom-right'` | `'bottom-right'` |
|
|
1436
|
+
| `richColors` | `boolean` — per-type coloring (deviates from the Spartan default) | `true` |
|
|
1437
|
+
| `theme` | `'light'|'dark'|'system'` | `'light'` |
|
|
1438
|
+
| `duration` | `number` — ms | `4000` |
|
|
1439
|
+
| `visibleToasts` | `number` | `3` |
|
|
1440
|
+
| `closeButton` | `boolean` | `false` |
|
|
1441
|
+
| `expand` | `boolean` — keeps the stack expanded | `false` |
|
|
1442
|
+
| `toastOptions` | `ToastOptions` — defaults applied to every toast | `{}` |
|
|
1443
|
+
|
|
1444
|
+
## Utilities and services
|
|
1445
|
+
|
|
1446
|
+
| Export | Description |
|
|
1447
|
+
|:--------------------------|:-----------------------------------------------------------------------------------------------|
|
|
1448
|
+
| `cn(...classes)` | `clsx` + `tailwind-merge`. Merges class lists so a later class overrides an earlier one of the same Tailwind group. |
|
|
1449
|
+
| `yuwToast` | Toast API (`success`, `error`, `warning`, `info`, `promise`, …). |
|
|
1450
|
+
| `YuwSidebarService` | Sidebar open/collapsed state, shared across the page. |
|
|
1451
|
+
| `provideYuwSidebarConfig` | App-wide sidebar defaults (widths, variant). |
|
|
1452
|
+
| `provideValueAccessor` | Registers a component as a form control — used by the library's own controls. |
|
|
1453
|
+
| `getPaginationRange` | The page/ellipsis sequence `<yuw-pagination>` renders. |
|
|
1454
|
+
| `YuwColorDto`, `YuwInputTypeDto`, `YuwInputModeDto`, `YuwTextFieldContract` | Shared type vocabulary. |
|
|
1455
|
+
|
|
1456
|
+
### Spartan helm layer
|
|
1457
|
+
|
|
1458
|
+
The Spartan **helm** layer this library builds on is compiled into the package itself as secondary
|
|
1459
|
+
entry points (`yukit-web/helm/button`, `yukit-web/helm/input`, …). Consumers don't need it — the
|
|
1460
|
+
`yuw-*` components are the supported API — but it is public and safe to import when you need a
|
|
1461
|
+
primitive no wrapper covers yet:
|
|
1462
|
+
|
|
1463
|
+
```ts
|
|
1464
|
+
import { HlmButton } from 'yukit-web/helm/button';
|
|
1465
|
+
```
|