@conciso/design-system-angular 0.0.0-bootstrap.0 → 2.1.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.
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { signal, Injectable, input, output, computed, ChangeDetectionStrategy, Component, inject, ElementRef, model, Directive, forwardRef, DestroyRef, viewChild, linkedSignal, numberAttribute, afterNextRender, TemplateRef, contentChildren, effect, viewChildren, afterRenderEffect } from '@angular/core';
|
|
3
3
|
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
4
4
|
import { provideIcons, NgIcon } from '@ng-icons/core';
|
|
5
|
-
import {
|
|
5
|
+
import { uiCaretDown as uiCaretDown$1, uiCheck as uiCheck$1 } from '@conciso/design-system/icons';
|
|
6
6
|
import { heroComputerDesktop, heroMoon, heroSun, heroXMark, heroMagnifyingGlass, heroBars3, heroChevronDown } from '@ng-icons/heroicons/outline';
|
|
7
7
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
8
8
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
@@ -203,6 +203,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
203
203
|
* · `ui-caret-down` — kräftiger Caret (10er-viewBox), kein Heroicon-Pendant.
|
|
204
204
|
* · `ui-check` — eigener Haken (12er-viewBox), weicht vom heroCheck (24er) ab.
|
|
205
205
|
*
|
|
206
|
+
* Importiert werden ausschließlich die BENANNTEN Exporte der beiden gebrauchten Glyphen
|
|
207
|
+
* (`uiCaretDown`, `uiCheck`), nie das aggregierte `icons`-Objekt — ein Property-Zugriff
|
|
208
|
+
* darauf (`icons['ui-caret-down']`) ist für Bundler nicht tree-shakable und zöge alle
|
|
209
|
+
* alle DS-Icons in jedes Consumer-Bundle (siehe icons/README.md „Verwendung“).
|
|
210
|
+
*
|
|
206
211
|
* 2. **Heroicons**: für Glyphen, die im DS mit dem Heroicon glyph-identisch sind
|
|
207
212
|
* (chevron-down, magnifying-glass — gleicher Pfad, das DS setzt nur einen dünneren
|
|
208
213
|
* Stroke) sowie für die im DS-Set (noch) fehlenden Chrome-Icons (bars-3, x-mark,
|
|
@@ -212,13 +217,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
212
217
|
* Komponenten importieren ausschließlich aus dieser Datei, nie direkt aus
|
|
213
218
|
* `@ng-icons/heroicons`.
|
|
214
219
|
*/
|
|
215
|
-
//
|
|
216
|
-
// eigene Typdeklaration; die Form ist in ds-icons-export.d.ts dokumentiert (ngtsc greift die
|
|
217
|
-
// Ambient-Deklaration dort nicht, anders als tsc, deshalb die explizite Unterdrückung hier).
|
|
218
|
-
// DS-eigene Glyphen aus dem generierten Export (kein Duplizieren des SVG-Markups).
|
|
220
|
+
// DS-eigene Glyphen aus dem generierten, benannten Export (kein Duplizieren des SVG-Markups).
|
|
219
221
|
// Als @ng-icons-Custom-Icons registrierbar: der Wert ist das komplette <svg>-Markup.
|
|
220
|
-
const uiCaretDown =
|
|
221
|
-
const uiCheck =
|
|
222
|
+
const uiCaretDown = uiCaretDown$1.svg;
|
|
223
|
+
const uiCheck = uiCheck$1.svg;
|
|
222
224
|
|
|
223
225
|
/**
|
|
224
226
|
* Theme-Cycle-Button — ein einzelner Icon-Button (Stil `.ep-nav-icon-btn` aus der
|
|
@@ -4286,34 +4288,106 @@ class ScaleComponent extends CvaBase {
|
|
|
4286
4288
|
outputClasses = computed(() => `field-slider-output slider-${this.area()}`, /* @ts-ignore */
|
|
4287
4289
|
...(ngDevMode ? [{ debugName: "outputClasses" }] : /* istanbul ignore next */ []));
|
|
4288
4290
|
/**
|
|
4289
|
-
*
|
|
4290
|
-
*
|
|
4291
|
-
*
|
|
4292
|
-
*
|
|
4293
|
-
*
|
|
4291
|
+
* Spaltenbreiten für das Tick-Grid, mit `minmax()` statt fixer Breiten: Bei
|
|
4292
|
+
* ausreichend Platz treffen die Spaltenmitten exakt die Thumb-Positionen (wie
|
|
4293
|
+
* bisher); wird es zu schmal, um alle Labels einzeilig zu zeigen, gibt das Grid
|
|
4294
|
+
* Lesbarkeit den Vorrang vor exakter Ausrichtung (Entscheidung: Umbruch statt
|
|
4295
|
+
* Überlappung ODER Abschneiden).
|
|
4296
|
+
*
|
|
4297
|
+
* - Rand-Spalten: `minmax(halber Schritt + 11px, max-content)`. Der Mindestwert ist
|
|
4298
|
+
* wie zuvor die halbe „Schritt“-Distanz `(100% − 22px) / (n − 1)` zwischen zwei
|
|
4299
|
+
* benachbarten Thumb-Positionen plus 11px (halbe Thumb-Breite, siehe
|
|
4300
|
+
* css/components.css) — das kantenbündige Rand-Label beansprucht nur EINE
|
|
4301
|
+
* Richtung, die Gegenseite (vor der ersten/nach der letzten Thumb-Position) fließt
|
|
4302
|
+
* seiner Spalte zu. Bei breiten Containern übersteigt dieser Mindestwert die
|
|
4303
|
+
* natürliche (einzeilige) Breite des Labels — dann klemmt `minmax()` laut Spezifikation
|
|
4304
|
+
* auf den Mindestwert, die Spalte verhält sich also identisch zu vorher. Erst wenn
|
|
4305
|
+
* der Container schmaler wird als diese Mindestbreite, wächst die Spalte auf bis
|
|
4306
|
+
* zu `max-content`, das Label bleibt einzeilig, solange noch Platz da ist.
|
|
4307
|
+
* - Mitte-Spalten: `minmax(min-content, 1fr)` — nie schmäler als das breiteste
|
|
4308
|
+
* unteilbare Wort, sonst gleichberechtigt (1fr) um den verbleibenden Platz. Bei
|
|
4309
|
+
* schmalen Breiten kann die Spalte dadurch von ihrem rechnerischen Schritt
|
|
4310
|
+
* abweichen; die Spaltenmitte (und damit das zentrierte Label) liegt dann
|
|
4311
|
+
* geringfügig neben der Thumb-Position — akzeptierter Trade-off.
|
|
4312
|
+
*
|
|
4313
|
+
* Bei nur einem Label eine volle Spalte.
|
|
4314
|
+
*
|
|
4315
|
+
* @internal
|
|
4316
|
+
*/
|
|
4317
|
+
tickColumns = computed(() => {
|
|
4318
|
+
const n = this.labels().length;
|
|
4319
|
+
if (n <= 1)
|
|
4320
|
+
return '1fr';
|
|
4321
|
+
const gaps = n - 1;
|
|
4322
|
+
const edge = `minmax(calc(11px + (100% - 22px) / ${gaps} / 2), max-content)`;
|
|
4323
|
+
if (n === 2)
|
|
4324
|
+
return `${edge} ${edge}`;
|
|
4325
|
+
const mid = `repeat(${n - 2}, minmax(min-content, 1fr))`;
|
|
4326
|
+
return `${edge} ${mid} ${edge}`;
|
|
4327
|
+
}, /* @ts-ignore */
|
|
4328
|
+
...(ngDevMode ? [{ debugName: "tickColumns" }] : /* istanbul ignore next */ []));
|
|
4329
|
+
/**
|
|
4330
|
+
* Alle Labels + Ausrichtung innerhalb ihrer Grid-Spalte (`tickColumns()`). Mitte-
|
|
4331
|
+
* Labels sind in ihrer Spalte zentriert — bei ausreichend Platz liegt die
|
|
4332
|
+
* Spaltenmitte exakt auf der Thumb-Position; bei sehr schmalen Breiten, wenn
|
|
4333
|
+
* `minmax(min-content, 1fr)` eine Spalte über ihren rechnerischen Schritt hinaus
|
|
4334
|
+
* wachsen lässt, kann die Mitte geringfügig davon abweichen (siehe
|
|
4335
|
+
* `tickColumns()`). Das ERSTE/LETZTE Label wird an der jeweiligen Kante verankert
|
|
4336
|
+
* (linksbündig bzw. rechtsbündig, 11px Innenabstand = halbe Thumb-Breite), damit
|
|
4337
|
+
* lange Kategorie-Labels an den Enden nicht über den Rand hinaus abgeschnitten
|
|
4338
|
+
* werden.
|
|
4339
|
+
*
|
|
4340
|
+
* Zusätzlich 4px `padding-inline` an der jeweils INNEREN Seite (Mitte-Labels:
|
|
4341
|
+
* beidseitig — bei zentriertem Text bleibt die Mitte dadurch unverschoben):
|
|
4342
|
+
* Mindestabstand zwischen benachbarten Labels. Ohne das können bei mittleren
|
|
4343
|
+
* Breiten (Spalte klemmt schon auf `minmax()`-Mindestwert, aber Label füllt sie
|
|
4344
|
+
* fast aus) die Text-Ink-Boxes zweier Nachbarn exakt aneinanderstoßen (0px Lücke,
|
|
4345
|
+
* liest sich als ein zusammengeschriebenes Wort), obwohl sie sich nicht
|
|
4346
|
+
* überlappen. `box-sizing:border-box` (s. u.) sorgt dafür, dass `min-content` in
|
|
4347
|
+
* `tickColumns()` das Padding mit einrechnet, statt die Spalte zusätzlich zu
|
|
4348
|
+
* stauchen.
|
|
4349
|
+
*
|
|
4350
|
+
* `hyphens:auto` trennt einzelne Wörter, die trotz der `max-content`/
|
|
4351
|
+
* `min-content`-Untergrenze in `tickColumns()` noch breiter als ihre Spalte sind —
|
|
4352
|
+
* wirkt nur, wenn die einbettende Seite `lang="de"` setzt (Storybooks Vitest-Iframe
|
|
4353
|
+
* tut das nicht; bei Konsumenten ist es nicht garantiert, daher rein additiv).
|
|
4354
|
+
* Bewusst OHNE `overflow-wrap:break-word`: das bricht mitten im Wort ohne
|
|
4355
|
+
* Trennzeichen (z. B. „zufriede“/„n“) und ist schlechter lesbar als ein Wort, das
|
|
4356
|
+
* im Ausnahmefall über seine Spalte hinausragt — Lesbarkeit vor exakter
|
|
4357
|
+
* Breiteneinhaltung. Ohne `white-space:nowrap` umbrechen Labels normal (zeilenweise),
|
|
4358
|
+
* statt sich zu überlagern.
|
|
4294
4359
|
*
|
|
4295
4360
|
* @internal
|
|
4296
4361
|
*/
|
|
4297
4362
|
tickItems = computed(() => {
|
|
4298
4363
|
const labels = this.labels();
|
|
4299
4364
|
const n = labels.length;
|
|
4300
|
-
|
|
4301
|
-
//
|
|
4302
|
-
//
|
|
4303
|
-
|
|
4365
|
+
// position/transform/white-space aus .field-slider-ticks>* (components.css)
|
|
4366
|
+
// explizit neutralisieren — sonst bleiben die Labels absolut positioniert und
|
|
4367
|
+
// ignorieren die Grid-Spalten, auf denen dieser Ansatz aufbaut.
|
|
4368
|
+
const base = {
|
|
4369
|
+
position: 'static',
|
|
4370
|
+
transform: 'none',
|
|
4371
|
+
'white-space': 'normal',
|
|
4372
|
+
'box-sizing': 'border-box',
|
|
4373
|
+
hyphens: 'auto',
|
|
4374
|
+
};
|
|
4304
4375
|
return labels.map((label, i) => {
|
|
4305
|
-
if (n <= 1
|
|
4306
|
-
return { label, style: { ...base,
|
|
4376
|
+
if (n <= 1)
|
|
4377
|
+
return { label, style: { ...base, 'text-align': 'left', 'padding-left': '11px' } };
|
|
4378
|
+
if (i === 0)
|
|
4379
|
+
// Innere Seite (rechts, Richtung nächstes Label) zusätzlich 4px — Mindestlücke,
|
|
4380
|
+
// s. Kommentar oben.
|
|
4381
|
+
return {
|
|
4382
|
+
label,
|
|
4383
|
+
style: { ...base, 'text-align': 'left', 'padding-left': '11px', 'padding-right': '4px' },
|
|
4384
|
+
};
|
|
4307
4385
|
if (i === n - 1)
|
|
4308
4386
|
return {
|
|
4309
4387
|
label,
|
|
4310
|
-
style: { ...base,
|
|
4388
|
+
style: { ...base, 'text-align': 'right', 'padding-left': '4px', 'padding-right': '11px' },
|
|
4311
4389
|
};
|
|
4312
|
-
|
|
4313
|
-
return {
|
|
4314
|
-
label,
|
|
4315
|
-
style: { ...base, left: `calc(11px + ${p} * (100% - 22px))`, transform: 'translateX(-50%)' },
|
|
4316
|
-
};
|
|
4390
|
+
return { label, style: { ...base, 'text-align': 'center', 'padding-inline': '4px' } };
|
|
4317
4391
|
});
|
|
4318
4392
|
}, /* @ts-ignore */
|
|
4319
4393
|
...(ngDevMode ? [{ debugName: "tickItems" }] : /* istanbul ignore next */ []));
|
|
@@ -4351,14 +4425,21 @@ class ScaleComponent extends CvaBase {
|
|
|
4351
4425
|
(blur)="markTouched()"
|
|
4352
4426
|
/>
|
|
4353
4427
|
@if (labels().length) {
|
|
4354
|
-
<!-- Alle Skalen-Labels
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4428
|
+
<!-- Alle Skalen-Labels als CSS-Grid-Spalten (Breiten: tickColumns()), bei
|
|
4429
|
+
ausreichend Platz exakt auf ihre Thumb-Position ausgerichtet (Thumb 22px,
|
|
4430
|
+
siehe css/components.css); bei schmalen Breiten gibt das Grid lieber den
|
|
4431
|
+
Umbruch frei, statt Labels zu überlagern oder abzuschneiden (siehe dort).
|
|
4432
|
+
KEINE Reduktion — jedes Label ist wählbar, PFLICHT-Inhalt (kein Dropping
|
|
4433
|
+
wie bei cds-slider). Statt Absolut-Positionierung Normalfluss: mehrzeilige
|
|
4434
|
+
Labels (lange Kategorien bei schmaler Breite) wachsen den Container in der
|
|
4435
|
+
Höhe und schieben nachfolgenden Inhalt nach unten, statt ihn zu
|
|
4436
|
+
überlagern. Self-contained positioniert (der --tick-p-Kernmechanismus liegt
|
|
4437
|
+
noch auf dem main-PR; nach Merge kann das vereinfacht werden). -->
|
|
4358
4438
|
<div
|
|
4359
4439
|
class="field-slider-ticks"
|
|
4360
4440
|
aria-hidden="true"
|
|
4361
|
-
style="position:relative;display:
|
|
4441
|
+
style="position:relative;display:grid;padding:0;height:auto;align-items:start"
|
|
4442
|
+
[style.grid-template-columns]="tickColumns()"
|
|
4362
4443
|
>
|
|
4363
4444
|
@for (t of tickItems(); track $index) {
|
|
4364
4445
|
<span [style]="t.style">{{ t.label }}</span>
|
|
@@ -4400,14 +4481,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
4400
4481
|
(blur)="markTouched()"
|
|
4401
4482
|
/>
|
|
4402
4483
|
@if (labels().length) {
|
|
4403
|
-
<!-- Alle Skalen-Labels
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4484
|
+
<!-- Alle Skalen-Labels als CSS-Grid-Spalten (Breiten: tickColumns()), bei
|
|
4485
|
+
ausreichend Platz exakt auf ihre Thumb-Position ausgerichtet (Thumb 22px,
|
|
4486
|
+
siehe css/components.css); bei schmalen Breiten gibt das Grid lieber den
|
|
4487
|
+
Umbruch frei, statt Labels zu überlagern oder abzuschneiden (siehe dort).
|
|
4488
|
+
KEINE Reduktion — jedes Label ist wählbar, PFLICHT-Inhalt (kein Dropping
|
|
4489
|
+
wie bei cds-slider). Statt Absolut-Positionierung Normalfluss: mehrzeilige
|
|
4490
|
+
Labels (lange Kategorien bei schmaler Breite) wachsen den Container in der
|
|
4491
|
+
Höhe und schieben nachfolgenden Inhalt nach unten, statt ihn zu
|
|
4492
|
+
überlagern. Self-contained positioniert (der --tick-p-Kernmechanismus liegt
|
|
4493
|
+
noch auf dem main-PR; nach Merge kann das vereinfacht werden). -->
|
|
4407
4494
|
<div
|
|
4408
4495
|
class="field-slider-ticks"
|
|
4409
4496
|
aria-hidden="true"
|
|
4410
|
-
style="position:relative;display:
|
|
4497
|
+
style="position:relative;display:grid;padding:0;height:auto;align-items:start"
|
|
4498
|
+
[style.grid-template-columns]="tickColumns()"
|
|
4411
4499
|
>
|
|
4412
4500
|
@for (t of tickItems(); track $index) {
|
|
4413
4501
|
<span [style]="t.style">{{ t.label }}</span>
|
|
@@ -4450,11 +4538,13 @@ class SnackbarComponent {
|
|
|
4450
4538
|
isError = computed(() => this.tone() === 'err', /* @ts-ignore */
|
|
4451
4539
|
...(ngDevMode ? [{ debugName: "isError" }] : /* istanbul ignore next */ []));
|
|
4452
4540
|
/**
|
|
4453
|
-
* Tonfarbe des Icons (wie im Doku-Markup).
|
|
4541
|
+
* Tonfarbe des Icons (wie im Doku-Markup). CSS-Variablen statt Hex (Befund 04) — als
|
|
4542
|
+
* [style.stroke] gesetzt, nicht als Präsentationsattribut, weil Präsentationsattribute var()
|
|
4543
|
+
* nicht auflösen.
|
|
4454
4544
|
*
|
|
4455
4545
|
* @internal
|
|
4456
4546
|
*/
|
|
4457
|
-
iconStroke = computed(() => ({ def: '
|
|
4547
|
+
iconStroke = computed(() => ({ def: 'var(--co-200)', ok: 'var(--c-success-strong-icon)', err: 'var(--c-error-strong-icon)' })[this.tone()], /* @ts-ignore */
|
|
4458
4548
|
...(ngDevMode ? [{ debugName: "iconStroke" }] : /* istanbul ignore next */ []));
|
|
4459
4549
|
/**
|
|
4460
4550
|
* Lucide-artiger Pfad je Ton (Glühbirne / Häkchen-Kreis / Ausrufezeichen-Kreis).
|
|
@@ -4479,7 +4569,7 @@ class SnackbarComponent {
|
|
|
4479
4569
|
height="24"
|
|
4480
4570
|
viewBox="0 0 24 24"
|
|
4481
4571
|
fill="none"
|
|
4482
|
-
[
|
|
4572
|
+
[style.stroke]="iconStroke()"
|
|
4483
4573
|
stroke-width="1.25"
|
|
4484
4574
|
aria-hidden="true"
|
|
4485
4575
|
focusable="false"
|
|
@@ -4510,7 +4600,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
4510
4600
|
height="24"
|
|
4511
4601
|
viewBox="0 0 24 24"
|
|
4512
4602
|
fill="none"
|
|
4513
|
-
[
|
|
4603
|
+
[style.stroke]="iconStroke()"
|
|
4514
4604
|
stroke-width="1.25"
|
|
4515
4605
|
aria-hidden="true"
|
|
4516
4606
|
focusable="false"
|