@skra/ui 0.2.0 → 0.3.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/LICENSE +201 -201
- package/NOTICE +7 -7
- package/README.md +39 -39
- package/consumer-guide/README.md +84 -84
- package/consumer-guide/forms-and-binding.md +19 -3
- package/consumer-guide/layout.md +19 -0
- package/consumer-guide/overlays.md +100 -100
- package/consumer-guide/setup-and-gotchas.md +165 -103
- package/consumer-guide/theming-and-encapsulation.md +129 -115
- package/fesm2022/skra-ui-accordion.mjs +61 -43
- package/fesm2022/skra-ui-accordion.mjs.map +1 -1
- package/fesm2022/skra-ui-alert.mjs +26 -18
- package/fesm2022/skra-ui-alert.mjs.map +1 -1
- package/fesm2022/skra-ui-avatar.mjs +12 -8
- package/fesm2022/skra-ui-avatar.mjs.map +1 -1
- package/fesm2022/skra-ui-badge.mjs +19 -13
- package/fesm2022/skra-ui-badge.mjs.map +1 -1
- package/fesm2022/skra-ui-button.mjs +28 -19
- package/fesm2022/skra-ui-button.mjs.map +1 -1
- package/fesm2022/skra-ui-checkbox.mjs +3 -3
- package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
- package/fesm2022/skra-ui-chip.mjs +15 -11
- package/fesm2022/skra-ui-chip.mjs.map +1 -1
- package/fesm2022/skra-ui-combobox.mjs +135 -130
- package/fesm2022/skra-ui-combobox.mjs.map +1 -1
- package/fesm2022/skra-ui-core.mjs +95 -73
- package/fesm2022/skra-ui-core.mjs.map +1 -1
- package/fesm2022/skra-ui-counter.mjs +9 -6
- package/fesm2022/skra-ui-counter.mjs.map +1 -1
- package/fesm2022/skra-ui-datepicker.mjs +334 -307
- package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
- package/fesm2022/skra-ui-dialog.mjs +5 -4
- package/fesm2022/skra-ui-dialog.mjs.map +1 -1
- package/fesm2022/skra-ui-field.mjs +65 -43
- package/fesm2022/skra-ui-field.mjs.map +1 -1
- package/fesm2022/skra-ui-icon.mjs +5 -4
- package/fesm2022/skra-ui-icon.mjs.map +1 -1
- package/fesm2022/skra-ui-input.mjs +53 -12
- package/fesm2022/skra-ui-input.mjs.map +1 -1
- package/fesm2022/skra-ui-kbd.mjs +3 -3
- package/fesm2022/skra-ui-kbd.mjs.map +1 -1
- package/fesm2022/skra-ui-layout.mjs +33 -21
- package/fesm2022/skra-ui-layout.mjs.map +1 -1
- package/fesm2022/skra-ui-link.mjs +3 -3
- package/fesm2022/skra-ui-link.mjs.map +1 -1
- package/fesm2022/skra-ui-loading-indicator.mjs +3 -3
- package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
- package/fesm2022/skra-ui-menu.mjs +8 -7
- package/fesm2022/skra-ui-menu.mjs.map +1 -1
- package/fesm2022/skra-ui-multi-select.mjs +102 -98
- package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
- package/fesm2022/skra-ui-native-select.mjs +35 -17
- package/fesm2022/skra-ui-native-select.mjs.map +1 -1
- package/fesm2022/skra-ui-popover.mjs +5 -4
- package/fesm2022/skra-ui-popover.mjs.map +1 -1
- package/fesm2022/skra-ui-progress.mjs +7 -5
- package/fesm2022/skra-ui-progress.mjs.map +1 -1
- package/fesm2022/skra-ui-radio.mjs +3 -3
- package/fesm2022/skra-ui-radio.mjs.map +1 -1
- package/fesm2022/skra-ui-rating-display.mjs +14 -9
- package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
- package/fesm2022/skra-ui-select.mjs +98 -95
- package/fesm2022/skra-ui-select.mjs.map +1 -1
- package/fesm2022/skra-ui-skeleton.mjs +16 -13
- package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
- package/fesm2022/skra-ui-star-rating.mjs +18 -11
- package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
- package/fesm2022/skra-ui-status-dot.mjs +7 -5
- package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
- package/fesm2022/skra-ui-switch.mjs +3 -3
- package/fesm2022/skra-ui-switch.mjs.map +1 -1
- package/fesm2022/skra-ui-tabs.mjs +43 -29
- package/fesm2022/skra-ui-tabs.mjs.map +1 -1
- package/fesm2022/skra-ui-textarea.mjs +41 -15
- package/fesm2022/skra-ui-textarea.mjs.map +1 -1
- package/fesm2022/skra-ui-toast.mjs +35 -23
- package/fesm2022/skra-ui-toast.mjs.map +1 -1
- package/fesm2022/skra-ui-tooltip.mjs +12 -9
- package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
- package/fesm2022/skra-ui-typography.mjs +9 -6
- package/fesm2022/skra-ui-typography.mjs.map +1 -1
- package/package.json +6 -6
- package/types/skra-ui-field.d.ts +3 -3
- package/types/skra-ui-field.d.ts.map +1 -1
- package/types/skra-ui-input.d.ts +24 -1
- package/types/skra-ui-input.d.ts.map +1 -1
- package/types/skra-ui-native-select.d.ts +9 -1
- package/types/skra-ui-native-select.d.ts.map +1 -1
- package/types/skra-ui-textarea.d.ts +10 -1
- package/types/skra-ui-textarea.d.ts.map +1 -1
|
@@ -40,18 +40,24 @@ class SkraStarRating {
|
|
|
40
40
|
idGen = inject(IdGeneratorService);
|
|
41
41
|
context = inject(SkraFieldContext, { optional: true });
|
|
42
42
|
/** Committed rating; 0 (or out of [1,max]) = unrated. Consumer-owned, controlled (ADR 037). */
|
|
43
|
-
value = input(0,
|
|
43
|
+
value = input(0, /* @ts-ignore */
|
|
44
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
44
45
|
/** Number of stars. Semantic count, not a look-input. */
|
|
45
|
-
max = input(5,
|
|
46
|
+
max = input(5, /* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
46
48
|
/** ADR 035 size axis — the only variant axis. */
|
|
47
|
-
size = input('md',
|
|
49
|
+
size = input('md', /* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
48
51
|
/** Fires on USER selection only (never on programmatic [value] changes). */
|
|
49
52
|
valueChange = output();
|
|
50
53
|
fallbackName = this.idGen.nextId('rating');
|
|
51
54
|
/** Unique radio-group name so multiple ratings on a page don't merge. */
|
|
52
|
-
groupName = computed(() => this.context?.fieldId() || this.fallbackName,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
groupName = computed(() => this.context?.fieldId() || this.fallbackName, /* @ts-ignore */
|
|
56
|
+
...(ngDevMode ? [{ debugName: "groupName" }] : /* istanbul ignore next */ []));
|
|
57
|
+
isDisabled = computed(() => this.context?.isDisabled() ?? false, /* @ts-ignore */
|
|
58
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
59
|
+
isReadonly = computed(() => this.context?.isReadonly() ?? false, /* @ts-ignore */
|
|
60
|
+
...(ngDevMode ? [{ debugName: "isReadonly" }] : /* istanbul ignore next */ []));
|
|
55
61
|
/**
|
|
56
62
|
* Star values HIGH→LOW (`[max, …, 1]`) so the CSS sibling combinator
|
|
57
63
|
* `input:checked ~ label` fills the checked star and every lower one. The visual
|
|
@@ -60,7 +66,8 @@ class SkraStarRating {
|
|
|
60
66
|
stars = computed(() => {
|
|
61
67
|
const n = Math.max(0, Math.floor(this.max()));
|
|
62
68
|
return Array.from({ length: n }, (_, i) => n - i);
|
|
63
|
-
},
|
|
69
|
+
}, /* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "stars" }] : /* istanbul ignore next */ []));
|
|
64
71
|
starLabel(star) {
|
|
65
72
|
return star === 1 ? '1 star' : `${star} stars`;
|
|
66
73
|
}
|
|
@@ -77,10 +84,10 @@ class SkraStarRating {
|
|
|
77
84
|
if (this.isReadonly() && event.key !== 'Tab')
|
|
78
85
|
event.preventDefault();
|
|
79
86
|
}
|
|
80
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
81
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
87
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraStarRating, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
88
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraStarRating, isStandalone: true, selector: "skra-star-rating", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { attributes: { "role": "radiogroup" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.aria-labelledby": "context?.labelId() ?? null", "attr.aria-required": "context?.isRequired() ? \"true\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null", "attr.data-skra-disabled": "isDisabled() ? \"\" : null", "attr.data-skra-size": "size()", "attr.id": "context?.fieldId() ?? null" } }, ngImport: i0, template: "@for (star of stars(); track star) {\r\n<input\r\n type=\"radio\"\r\n class=\"skra-star-rating-input\"\r\n [name]=\"groupName()\"\r\n [id]=\"groupName() + '-' + star\"\r\n [value]=\"star\"\r\n [checked]=\"value() === star\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"starLabel(star)\"\r\n (change)=\"onSelect(star)\"\r\n/>\r\n<label\r\n class=\"skra-star-rating-star\"\r\n [attr.for]=\"groupName() + '-' + star\"\r\n aria-hidden=\"true\"\r\n>\r\n <svg\r\n class=\"skra-star-rating-glyph\"\r\n viewBox=\"0 0 24 24\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\"\r\n />\r\n </svg>\r\n</label>\r\n}\r\n", styles: [":host{margin:0;display:inline-flex;flex-direction:row-reverse;align-items:center;gap:var(--skra-comp-star-rating-gap);--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=sm]){--_star-size: var(--skra-comp-star-rating-star-size-sm)}:host([data-skra-size=md]){--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=lg]){--_star-size: var(--skra-comp-star-rating-star-size-lg)}:host([data-skra-disabled]){opacity:var(--skra-sys-opacity-disabled);cursor:not-allowed}.skra-star-rating-input{position:absolute;inline-size:1px;block-size:1px;margin:0;padding:0;opacity:0;pointer-events:none}.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty);display:inline-flex;cursor:pointer;line-height:0;border-radius:.125rem}.skra-star-rating-glyph{inline-size:var(--_star-size);block-size:var(--_star-size);fill:var(--_fill);transition:fill var(--skra-comp-star-rating-motion-duration) var(--skra-comp-star-rating-motion-easing)}.skra-star-rating-input:checked~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover,:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host([aria-readonly=true]) .skra-star-rating-star{cursor:default}.skra-star-rating-input:focus-visible+.skra-star-rating-star{outline:var(--skra-comp-star-rating-focus-ring-width) solid var(--skra-comp-star-rating-focus-ring-color);outline-offset:.125rem}@media(prefers-reduced-motion:reduce){.skra-star-rating-glyph{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
82
89
|
}
|
|
83
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
90
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraStarRating, decorators: [{
|
|
84
91
|
type: Component,
|
|
85
92
|
args: [{ selector: 'skra-star-rating', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
86
93
|
role: 'radiogroup',
|
|
@@ -97,7 +104,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
97
104
|
// Blocks the toggle from pointer (click) and keyboard (arrows fire change directly).
|
|
98
105
|
'(click)': 'blockWhenReadonly($event)',
|
|
99
106
|
'(keydown)': 'blockKeyWhenReadonly($event)',
|
|
100
|
-
}, template: "@for (star of stars(); track star) {\n<input\n type=\"radio\"\n class=\"skra-star-rating-input\"\n [name]=\"groupName()\"\n [id]=\"groupName() + '-' + star\"\n [value]=\"star\"\n [checked]=\"value() === star\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"starLabel(star)\"\n (change)=\"onSelect(star)\"\n/>\n<label\n class=\"skra-star-rating-star\"\n [attr.for]=\"groupName() + '-' + star\"\n aria-hidden=\"true\"\n>\n <svg\n class=\"skra-star-rating-glyph\"\n viewBox=\"0 0 24 24\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\"\n />\n </svg>\n</label>\n}\n", styles: [":host{margin:0;display:inline-flex;flex-direction:row-reverse;align-items:center;gap:var(--skra-comp-star-rating-gap);--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=sm]){--_star-size: var(--skra-comp-star-rating-star-size-sm)}:host([data-skra-size=md]){--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=lg]){--_star-size: var(--skra-comp-star-rating-star-size-lg)}:host([data-skra-disabled]){opacity:var(--skra-sys-opacity-disabled);cursor:not-allowed}.skra-star-rating-input{position:absolute;inline-size:1px;block-size:1px;margin:0;padding:0;opacity:0;pointer-events:none}.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty);display:inline-flex;cursor:pointer;line-height:0;border-radius:.125rem}.skra-star-rating-glyph{inline-size:var(--_star-size);block-size:var(--_star-size);fill:var(--_fill);transition:fill var(--skra-comp-star-rating-motion-duration) var(--skra-comp-star-rating-motion-easing)}.skra-star-rating-input:checked~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover,:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host([aria-readonly=true]) .skra-star-rating-star{cursor:default}.skra-star-rating-input:focus-visible+.skra-star-rating-star{outline:var(--skra-comp-star-rating-focus-ring-width) solid var(--skra-comp-star-rating-focus-ring-color);outline-offset:.125rem}@media(prefers-reduced-motion:reduce){.skra-star-rating-glyph{transition:none}}\n"] }]
|
|
107
|
+
}, template: "@for (star of stars(); track star) {\r\n<input\r\n type=\"radio\"\r\n class=\"skra-star-rating-input\"\r\n [name]=\"groupName()\"\r\n [id]=\"groupName() + '-' + star\"\r\n [value]=\"star\"\r\n [checked]=\"value() === star\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"starLabel(star)\"\r\n (change)=\"onSelect(star)\"\r\n/>\r\n<label\r\n class=\"skra-star-rating-star\"\r\n [attr.for]=\"groupName() + '-' + star\"\r\n aria-hidden=\"true\"\r\n>\r\n <svg\r\n class=\"skra-star-rating-glyph\"\r\n viewBox=\"0 0 24 24\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\"\r\n />\r\n </svg>\r\n</label>\r\n}\r\n", styles: [":host{margin:0;display:inline-flex;flex-direction:row-reverse;align-items:center;gap:var(--skra-comp-star-rating-gap);--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=sm]){--_star-size: var(--skra-comp-star-rating-star-size-sm)}:host([data-skra-size=md]){--_star-size: var(--skra-comp-star-rating-star-size-md)}:host([data-skra-size=lg]){--_star-size: var(--skra-comp-star-rating-star-size-lg)}:host([data-skra-disabled]){opacity:var(--skra-sys-opacity-disabled);cursor:not-allowed}.skra-star-rating-input{position:absolute;inline-size:1px;block-size:1px;margin:0;padding:0;opacity:0;pointer-events:none}.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty);display:inline-flex;cursor:pointer;line-height:0;border-radius:.125rem}.skra-star-rating-glyph{inline-size:var(--_star-size);block-size:var(--_star-size);fill:var(--_fill);transition:fill var(--skra-comp-star-rating-motion-duration) var(--skra-comp-star-rating-motion-easing)}.skra-star-rating-input:checked~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-empty)}:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover,:host(:hover:not([aria-readonly=true]):not([data-skra-disabled])) .skra-star-rating-star:hover~.skra-star-rating-star{--_fill: var(--skra-comp-star-rating-star-color-filled)}:host([aria-readonly=true]) .skra-star-rating-star{cursor:default}.skra-star-rating-input:focus-visible+.skra-star-rating-star{outline:var(--skra-comp-star-rating-focus-ring-width) solid var(--skra-comp-star-rating-focus-ring-color);outline-offset:.125rem}@media(prefers-reduced-motion:reduce){.skra-star-rating-glyph{transition:none}}\n"] }]
|
|
101
108
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
102
109
|
|
|
103
110
|
// APG-radiogroup composite rendered as stars (ADR 039 §7).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-star-rating.mjs","sources":["../../../../libs/ui/star-rating/src/lib/star-rating/star-rating.ts","../../../../libs/ui/star-rating/src/lib/star-rating/star-rating.html","../../../../libs/ui/star-rating/src/index.ts","../../../../libs/ui/star-rating/src/skra-ui-star-rating.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\nimport { IdGeneratorService } from '@skra/ui/field';\n\nexport type StarRatingSize = 'sm' | 'md' | 'lg';\n\n/**\n * `<skra-star-rating>` — a whole-star rating **input**. An APG Rating composite\n * (`role=\"radiogroup\"`) rendered as stars: internally N `(input[type=radio] + label)`\n * pairs sharing one `name`, where the label IS the star glyph (inline SVG) and the\n * input is sr-only but focusable.\n *\n * Governed by the **ADR 039 §7 note (2026-06-24)**: a composite widget MAY render\n * internal native radios — this is NOT the §3.3-forbidden `<skra-radio-group>` —\n * because (1) value is consumer-owned (`[value]` / `(valueChange)`, controlled-only\n * per ADR 037, the Tabs `[selected]` precedent — no internal value-of-record signal),\n * (2) there is no `SkraRadioGroupContext`, (3) it is a distinct APG composite (like\n * `skra-select`), not a generic radio-group wrapper. Custom element justified per\n * ADR 012 — there is no native single host for a rating.\n *\n * <skra-field [hasError]=\"!form.rating()\">\n * <label skraLabelFor>Rate your experience</label>\n * <skra-star-rating [value]=\"form.rating()\" (valueChange)=\"form.rating.set($event)\" />\n * <skra-error>Please pick a rating</skra-error>\n * </skra-field>\n *\n * Keyboard is the **native radio group** (arrows move + select, wrap, single tab stop)\n * — ZERO CDK. The fill + hover-preview are **pure CSS** (`:checked`/`:hover` sibling\n * combinators) — CSP-clean (ADR 021), no `[style.--var]`, no TS for the preview. The\n * committed `aria-checked` is the only thing AT observes; hover-preview is visual-only.\n *\n * Optional `SkraFieldContext` (ADR 013): the radiogroup is named via `aria-labelledby`\n * → the field label (`SkraFieldContext.labelId`, since a radiogroup is not labelable by\n * `for`/`id`); `disabled`/`required`/`readonly`/`invalid`/`describedby` cascade. Value is\n * NEVER in the context (ADR 037). The `readonly` state shows a committed whole-star rating\n * without allowing change (\"show my 4★\").\n *\n * Whole-star only (half-step input deferred). Fractional aggregate display (\"4.3★\") is the\n * separate `skra-rating-display` atom (`libs/ui/data-display`).\n */\n@Component({\n selector: 'skra-star-rating',\n standalone: true,\n templateUrl: './star-rating.html',\n styleUrl: './star-rating.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'radiogroup',\n // Named by the field label (Path 1) — radiogroups are not labelable by for/id.\n '[attr.aria-labelledby]': 'context?.labelId() ?? null',\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '[attr.data-skra-disabled]': 'isDisabled() ? \"\" : null',\n '[attr.data-skra-size]': 'size()',\n '[attr.id]': 'context?.fieldId() ?? null',\n // Readonly enforcement — without it the announced aria-readonly would be a lie.\n // Blocks the toggle from pointer (click) and keyboard (arrows fire change directly).\n '(click)': 'blockWhenReadonly($event)',\n '(keydown)': 'blockKeyWhenReadonly($event)',\n },\n})\nexport class SkraStarRating {\n private readonly idGen = inject(IdGeneratorService);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n /** Committed rating; 0 (or out of [1,max]) = unrated. Consumer-owned, controlled (ADR 037). */\n readonly value = input<number>(0);\n /** Number of stars. Semantic count, not a look-input. */\n readonly max = input<number>(5);\n /** ADR 035 size axis — the only variant axis. */\n readonly size = input<StarRatingSize>('md');\n /** Fires on USER selection only (never on programmatic [value] changes). */\n readonly valueChange = output<number>();\n\n private readonly fallbackName = this.idGen.nextId('rating');\n /** Unique radio-group name so multiple ratings on a page don't merge. */\n readonly groupName = computed(\n () => this.context?.fieldId() || this.fallbackName,\n );\n\n readonly isDisabled = computed(() => this.context?.isDisabled() ?? false);\n readonly isReadonly = computed(() => this.context?.isReadonly() ?? false);\n\n /**\n * Star values HIGH→LOW (`[max, …, 1]`) so the CSS sibling combinator\n * `input:checked ~ label` fills the checked star and every lower one. The visual\n * order is restored left-to-right via `flex-direction: row-reverse` in the SCSS.\n */\n readonly stars = computed(() => {\n const n = Math.max(0, Math.floor(this.max()));\n return Array.from({ length: n }, (_, i) => n - i);\n });\n\n protected starLabel(star: number): string {\n return star === 1 ? '1 star' : `${star} stars`;\n }\n\n protected onSelect(star: number): void {\n // Reached only when not readonly (click/keydown are blocked below when readonly),\n // and never on programmatic [value] changes — so this is user-intent only.\n this.valueChange.emit(star);\n }\n\n protected blockWhenReadonly(event: Event): void {\n if (this.isReadonly()) event.preventDefault();\n }\n\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\n if (this.isReadonly() && event.key !== 'Tab') event.preventDefault();\n }\n}\n","@for (star of stars(); track star) {\n<input\n type=\"radio\"\n class=\"skra-star-rating-input\"\n [name]=\"groupName()\"\n [id]=\"groupName() + '-' + star\"\n [value]=\"star\"\n [checked]=\"value() === star\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"starLabel(star)\"\n (change)=\"onSelect(star)\"\n/>\n<label\n class=\"skra-star-rating-star\"\n [attr.for]=\"groupName() + '-' + star\"\n aria-hidden=\"true\"\n>\n <svg\n class=\"skra-star-rating-glyph\"\n viewBox=\"0 0 24 24\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\"\n />\n </svg>\n</label>\n}\n","// APG-radiogroup composite rendered as stars (ADR 039 §7).\r\nexport * from './lib/star-rating/star-rating';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MAyBU,cAAc,CAAA;AACR,IAAA,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAC1C,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;
|
|
1
|
+
{"version":3,"file":"skra-ui-star-rating.mjs","sources":["../../../../libs/ui/star-rating/src/lib/star-rating/star-rating.ts","../../../../libs/ui/star-rating/src/lib/star-rating/star-rating.html","../../../../libs/ui/star-rating/src/index.ts","../../../../libs/ui/star-rating/src/skra-ui-star-rating.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n computed,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '@skra/ui/field';\r\nimport { IdGeneratorService } from '@skra/ui/field';\r\n\r\nexport type StarRatingSize = 'sm' | 'md' | 'lg';\r\n\r\n/**\r\n * `<skra-star-rating>` — a whole-star rating **input**. An APG Rating composite\r\n * (`role=\"radiogroup\"`) rendered as stars: internally N `(input[type=radio] + label)`\r\n * pairs sharing one `name`, where the label IS the star glyph (inline SVG) and the\r\n * input is sr-only but focusable.\r\n *\r\n * Governed by the **ADR 039 §7 note (2026-06-24)**: a composite widget MAY render\r\n * internal native radios — this is NOT the §3.3-forbidden `<skra-radio-group>` —\r\n * because (1) value is consumer-owned (`[value]` / `(valueChange)`, controlled-only\r\n * per ADR 037, the Tabs `[selected]` precedent — no internal value-of-record signal),\r\n * (2) there is no `SkraRadioGroupContext`, (3) it is a distinct APG composite (like\r\n * `skra-select`), not a generic radio-group wrapper. Custom element justified per\r\n * ADR 012 — there is no native single host for a rating.\r\n *\r\n * <skra-field [hasError]=\"!form.rating()\">\r\n * <label skraLabelFor>Rate your experience</label>\r\n * <skra-star-rating [value]=\"form.rating()\" (valueChange)=\"form.rating.set($event)\" />\r\n * <skra-error>Please pick a rating</skra-error>\r\n * </skra-field>\r\n *\r\n * Keyboard is the **native radio group** (arrows move + select, wrap, single tab stop)\r\n * — ZERO CDK. The fill + hover-preview are **pure CSS** (`:checked`/`:hover` sibling\r\n * combinators) — CSP-clean (ADR 021), no `[style.--var]`, no TS for the preview. The\r\n * committed `aria-checked` is the only thing AT observes; hover-preview is visual-only.\r\n *\r\n * Optional `SkraFieldContext` (ADR 013): the radiogroup is named via `aria-labelledby`\r\n * → the field label (`SkraFieldContext.labelId`, since a radiogroup is not labelable by\r\n * `for`/`id`); `disabled`/`required`/`readonly`/`invalid`/`describedby` cascade. Value is\r\n * NEVER in the context (ADR 037). The `readonly` state shows a committed whole-star rating\r\n * without allowing change (\"show my 4★\").\r\n *\r\n * Whole-star only (half-step input deferred). Fractional aggregate display (\"4.3★\") is the\r\n * separate `skra-rating-display` atom (`libs/ui/data-display`).\r\n */\r\n@Component({\r\n selector: 'skra-star-rating',\r\n standalone: true,\r\n templateUrl: './star-rating.html',\r\n styleUrl: './star-rating.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'radiogroup',\r\n // Named by the field label (Path 1) — radiogroups are not labelable by for/id.\r\n '[attr.aria-labelledby]': 'context?.labelId() ?? null',\r\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\r\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\r\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\r\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\r\n '[attr.data-skra-disabled]': 'isDisabled() ? \"\" : null',\r\n '[attr.data-skra-size]': 'size()',\r\n '[attr.id]': 'context?.fieldId() ?? null',\r\n // Readonly enforcement — without it the announced aria-readonly would be a lie.\r\n // Blocks the toggle from pointer (click) and keyboard (arrows fire change directly).\r\n '(click)': 'blockWhenReadonly($event)',\r\n '(keydown)': 'blockKeyWhenReadonly($event)',\r\n },\r\n})\r\nexport class SkraStarRating {\r\n private readonly idGen = inject(IdGeneratorService);\r\n readonly context = inject(SkraFieldContext, { optional: true });\r\n\r\n /** Committed rating; 0 (or out of [1,max]) = unrated. Consumer-owned, controlled (ADR 037). */\r\n readonly value = input<number>(0);\r\n /** Number of stars. Semantic count, not a look-input. */\r\n readonly max = input<number>(5);\r\n /** ADR 035 size axis — the only variant axis. */\r\n readonly size = input<StarRatingSize>('md');\r\n /** Fires on USER selection only (never on programmatic [value] changes). */\r\n readonly valueChange = output<number>();\r\n\r\n private readonly fallbackName = this.idGen.nextId('rating');\r\n /** Unique radio-group name so multiple ratings on a page don't merge. */\r\n readonly groupName = computed(\r\n () => this.context?.fieldId() || this.fallbackName,\r\n );\r\n\r\n readonly isDisabled = computed(() => this.context?.isDisabled() ?? false);\r\n readonly isReadonly = computed(() => this.context?.isReadonly() ?? false);\r\n\r\n /**\r\n * Star values HIGH→LOW (`[max, …, 1]`) so the CSS sibling combinator\r\n * `input:checked ~ label` fills the checked star and every lower one. The visual\r\n * order is restored left-to-right via `flex-direction: row-reverse` in the SCSS.\r\n */\r\n readonly stars = computed(() => {\r\n const n = Math.max(0, Math.floor(this.max()));\r\n return Array.from({ length: n }, (_, i) => n - i);\r\n });\r\n\r\n protected starLabel(star: number): string {\r\n return star === 1 ? '1 star' : `${star} stars`;\r\n }\r\n\r\n protected onSelect(star: number): void {\r\n // Reached only when not readonly (click/keydown are blocked below when readonly),\r\n // and never on programmatic [value] changes — so this is user-intent only.\r\n this.valueChange.emit(star);\r\n }\r\n\r\n protected blockWhenReadonly(event: Event): void {\r\n if (this.isReadonly()) event.preventDefault();\r\n }\r\n\r\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\r\n if (this.isReadonly() && event.key !== 'Tab') event.preventDefault();\r\n }\r\n}\r\n","@for (star of stars(); track star) {\r\n<input\r\n type=\"radio\"\r\n class=\"skra-star-rating-input\"\r\n [name]=\"groupName()\"\r\n [id]=\"groupName() + '-' + star\"\r\n [value]=\"star\"\r\n [checked]=\"value() === star\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"starLabel(star)\"\r\n (change)=\"onSelect(star)\"\r\n/>\r\n<label\r\n class=\"skra-star-rating-star\"\r\n [attr.for]=\"groupName() + '-' + star\"\r\n aria-hidden=\"true\"\r\n>\r\n <svg\r\n class=\"skra-star-rating-glyph\"\r\n viewBox=\"0 0 24 24\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z\"\r\n />\r\n </svg>\r\n</label>\r\n}\r\n","// APG-radiogroup composite rendered as stars (ADR 039 §7).\r\nexport * from './lib/star-rating/star-rating';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MAyBU,cAAc,CAAA;AACR,IAAA,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAC1C,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;IAGtD,KAAK,GAAG,KAAK,CAAS,CAAC;8EAAC;;IAExB,GAAG,GAAG,KAAK,CAAS,CAAC;4EAAC;;IAEtB,IAAI,GAAG,KAAK,CAAiB,IAAI;6EAAC;;IAElC,WAAW,GAAG,MAAM,EAAU;IAEtB,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;;AAElD,IAAA,SAAS,GAAG,QAAQ,CAC3B,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,YAAY;kFACnD;AAEQ,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK;mFAAC;AAChE,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK;mFAAC;AAEzE;;;;AAIG;AACM,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAK;AAC7B,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;8EAAC;AAEQ,IAAA,SAAS,CAAC,IAAY,EAAA;AAC9B,QAAA,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,GAAG,CAAA,EAAG,IAAI,QAAQ;IAChD;AAEU,IAAA,QAAQ,CAAC,IAAY,EAAA;;;AAG7B,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B;AAEU,IAAA,iBAAiB,CAAC,KAAY,EAAA;QACtC,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IAC/C;AAEU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;QACjD,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;YAAE,KAAK,CAAC,cAAc,EAAE;IACtE;uGAhDW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,ujCCxE3B,kwBA6BA,EAAA,MAAA,EAAA,CAAA,0zDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FD2Ca,cAAc,EAAA,UAAA,EAAA,CAAA;kBAxB1B,SAAS;+BACE,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;AACJ,wBAAA,IAAI,EAAE,YAAY;;AAElB,wBAAA,wBAAwB,EAAE,4BAA4B;AACtD,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,qBAAqB,EAAE,qCAAqC;AAC5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,2BAA2B,EAAE,0BAA0B;AACvD,wBAAA,uBAAuB,EAAE,QAAQ;AACjC,wBAAA,WAAW,EAAE,4BAA4B;;;AAGzC,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,QAAA,EAAA,kwBAAA,EAAA,MAAA,EAAA,CAAA,0zDAAA,CAAA,EAAA;;;AEtEH;;ACAA;;AAEG;;;;"}
|
|
@@ -38,13 +38,15 @@ import { input, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@a
|
|
|
38
38
|
*/
|
|
39
39
|
class SkraStatusDot {
|
|
40
40
|
/** Variant Surface Intent axis (ADR 035) — the fill colour (status palette subset). */
|
|
41
|
-
intent = input('neutral',
|
|
41
|
+
intent = input('neutral', /* @ts-ignore */
|
|
42
|
+
...(ngDevMode ? [{ debugName: "intent" }] : /* istanbul ignore next */ []));
|
|
42
43
|
/** Variant Surface Size axis (ADR 035) — the dot's (colored core) diameter. */
|
|
43
|
-
size = input('md',
|
|
44
|
-
|
|
45
|
-
static
|
|
44
|
+
size = input('md', /* @ts-ignore */
|
|
45
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraStatusDot, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
47
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraStatusDot, isStandalone: true, selector: "skra-status-dot", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-size": "size()" } }, ngImport: i0, template: '', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-block;flex-shrink:0;box-sizing:content-box;margin:0;inline-size:var(--skra-comp-status-dot-size-md);block-size:var(--skra-comp-status-dot-size-md);background:var(--skra-comp-status-dot-background);border-color:var(--skra-comp-status-dot-border-color);border-width:var(--skra-comp-status-dot-border-width);border-style:var(--skra-comp-status-dot-border-style);border-radius:var(--skra-comp-status-dot-radius);padding-block:var(--skra-comp-status-dot-padding-block);padding-inline:var(--skra-comp-status-dot-padding-inline);box-shadow:var(--skra-comp-status-dot-shadow)}:host([data-skra-size=sm]){inline-size:var(--skra-comp-status-dot-size-sm);block-size:var(--skra-comp-status-dot-size-sm)}:host([data-skra-size=lg]){inline-size:var(--skra-comp-status-dot-size-lg);block-size:var(--skra-comp-status-dot-size-lg)}:host([data-skra-intent=info]){--skra-comp-status-dot-background: var(--skra-sys-color-info-base)}:host([data-skra-intent=success]){--skra-comp-status-dot-background: var(--skra-sys-color-success-base)}:host([data-skra-intent=warning]){--skra-comp-status-dot-background: var(--skra-sys-color-warning-base)}:host([data-skra-intent=danger]){--skra-comp-status-dot-background: var(--skra-sys-color-danger-base)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
46
48
|
}
|
|
47
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraStatusDot, decorators: [{
|
|
48
50
|
type: Component,
|
|
49
51
|
args: [{ selector: 'skra-status-dot', standalone: true, template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
50
52
|
// Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var]).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-status-dot.mjs","sources":["../../../../libs/ui/status-dot/src/lib/status-dot/status-dot.ts","../../../../libs/ui/status-dot/src/skra-ui-status-dot.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\n/**\n * StatusDotIntent — the Variant Surface Intent axis (ADR 035 §3.1, the status palette subset).\n * Drops the action intents `primary`/`secondary` (those belong to interactive surfaces, not a\n * status glyph). Closed enum; extension requires an ADR 035 amendment.\n */\nexport type StatusDotIntent =\n | 'neutral'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger';\n\n/**\n * StatusDotSize — the Variant Surface Size axis (ADR 035 §3.1, downward subset `sm|md|lg`).\n * `xs`/`xl` are reserved (ADR 035 §3.2) and NOT in MVP — adding them later is purely additive.\n * Unlike content-width Badge (which has no size — its size is its text), the dot has NO content,\n * so size is a genuine free variable the consumer needs (corner-of-`lg`-avatar vs inline-in-text).\n */\nexport type StatusDotSize = 'sm' | 'md' | 'lg';\n\n/**\n * `<skra-status-dot>` — a bare, small, non-interactive status/presence indicator (a coloured dot)\n * composed beside other content: an avatar corner (online/away/busy/offline), or beside a label.\n * Second resident of `libs/ui/data-display`, sibling to `<skra-avatar>` (whose corner presence-dot\n * it provides). See `adr/specs/component-status-dot-spec.md`.\n *\n * **Element, not a decorated native (ADR 012):** there is no native `<dot>`, and a bare `<span>`\n * carries no semantics and forces a colour literal. NOT a Web Component (ADR 000).\n *\n * **No content (the SRP line vs `skra-badge`):** the dot IS the glyph — no slots, no projected\n * content, no label/count. Meaning is carried by ADJACENT text the consumer owns. The defining\n * value-add over a hand-rolled span is the semantic `intent`→token-colour mapping (no hex — ADR\n * 002/023) + the size axis that tracks the avatar.\n *\n * **Non-interactive (Avatar/Badge precedent):** no focusable node, no widget role, no keyboard, no\n * outputs → State Surface all-N/A. A clickable status = `button[skraButton]` composition, not a\n * variant.\n *\n * **Accessible name (ADR 033 Path 3 — graphic host, the SkraIcon/Avatar contract):** the host\n * carries NO default ARIA. The consumer declares semantics explicitly, exactly as for\n * `<skra-icon>`/`<skra-avatar>`:\n * - decorative (Mode A, the ~90% case — dot beside visible/sr-only status text) → `aria-hidden=\"true\"`;\n * - meaningful (Mode B — the dot is the SOLE status carrier) → **`role=\"img\"` + `aria-label`/\n * `aria-labelledby` TOGETHER**. `role=\"img\"` is REQUIRED: `aria-label` on the roleless host is\n * ARIA-prohibited (axe `aria-prohibited-attr`, the Avatar Mode-B fix) and conveys no name.\n * WCAG 1.4.1 (colour-independence) cannot be enforced by the atom — the adjacent text is the\n * consumer's; the `InlineStatus`/`A11yCheck` stories carry the editorial contract. NO `ariaLabel`\n * input (ADR 033 boundary #8).\n *\n * **Look is skin-owned:** circle-vs-square is the `radius` comp token (brutal's `radius.full: 0`\n * ships a square dot automatically). The fill is the semantic `intent`→`sys.color.<intent>.base`\n * (recolour at the sys level, not a per-dot token — skin philosophy); NO `emphasis` (always filled),\n * NO `live` (a dot has no text to announce — the consumer's adjacent live text does), NO\n * `color`/`variant`/`shape` look-inputs.\n */\n@Component({\n selector: 'skra-status-dot',\n standalone: true,\n template: '',\n styleUrl: './status-dot.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var]).\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-size]': 'size()',\n },\n})\nexport class SkraStatusDot {\n /** Variant Surface Intent axis (ADR 035) — the fill colour (status palette subset). */\n readonly intent = input<StatusDotIntent>('neutral');\n\n /** Variant Surface Size axis (ADR 035) — the dot's (colored core) diameter. */\n readonly size = input<StatusDotSize>('md');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAcU,aAAa,CAAA;;
|
|
1
|
+
{"version":3,"file":"skra-ui-status-dot.mjs","sources":["../../../../libs/ui/status-dot/src/lib/status-dot/status-dot.ts","../../../../libs/ui/status-dot/src/skra-ui-status-dot.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\n/**\r\n * StatusDotIntent — the Variant Surface Intent axis (ADR 035 §3.1, the status palette subset).\r\n * Drops the action intents `primary`/`secondary` (those belong to interactive surfaces, not a\r\n * status glyph). Closed enum; extension requires an ADR 035 amendment.\r\n */\r\nexport type StatusDotIntent =\r\n | 'neutral'\r\n | 'info'\r\n | 'success'\r\n | 'warning'\r\n | 'danger';\r\n\r\n/**\r\n * StatusDotSize — the Variant Surface Size axis (ADR 035 §3.1, downward subset `sm|md|lg`).\r\n * `xs`/`xl` are reserved (ADR 035 §3.2) and NOT in MVP — adding them later is purely additive.\r\n * Unlike content-width Badge (which has no size — its size is its text), the dot has NO content,\r\n * so size is a genuine free variable the consumer needs (corner-of-`lg`-avatar vs inline-in-text).\r\n */\r\nexport type StatusDotSize = 'sm' | 'md' | 'lg';\r\n\r\n/**\r\n * `<skra-status-dot>` — a bare, small, non-interactive status/presence indicator (a coloured dot)\r\n * composed beside other content: an avatar corner (online/away/busy/offline), or beside a label.\r\n * Second resident of `libs/ui/data-display`, sibling to `<skra-avatar>` (whose corner presence-dot\r\n * it provides). See `adr/specs/component-status-dot-spec.md`.\r\n *\r\n * **Element, not a decorated native (ADR 012):** there is no native `<dot>`, and a bare `<span>`\r\n * carries no semantics and forces a colour literal. NOT a Web Component (ADR 000).\r\n *\r\n * **No content (the SRP line vs `skra-badge`):** the dot IS the glyph — no slots, no projected\r\n * content, no label/count. Meaning is carried by ADJACENT text the consumer owns. The defining\r\n * value-add over a hand-rolled span is the semantic `intent`→token-colour mapping (no hex — ADR\r\n * 002/023) + the size axis that tracks the avatar.\r\n *\r\n * **Non-interactive (Avatar/Badge precedent):** no focusable node, no widget role, no keyboard, no\r\n * outputs → State Surface all-N/A. A clickable status = `button[skraButton]` composition, not a\r\n * variant.\r\n *\r\n * **Accessible name (ADR 033 Path 3 — graphic host, the SkraIcon/Avatar contract):** the host\r\n * carries NO default ARIA. The consumer declares semantics explicitly, exactly as for\r\n * `<skra-icon>`/`<skra-avatar>`:\r\n * - decorative (Mode A, the ~90% case — dot beside visible/sr-only status text) → `aria-hidden=\"true\"`;\r\n * - meaningful (Mode B — the dot is the SOLE status carrier) → **`role=\"img\"` + `aria-label`/\r\n * `aria-labelledby` TOGETHER**. `role=\"img\"` is REQUIRED: `aria-label` on the roleless host is\r\n * ARIA-prohibited (axe `aria-prohibited-attr`, the Avatar Mode-B fix) and conveys no name.\r\n * WCAG 1.4.1 (colour-independence) cannot be enforced by the atom — the adjacent text is the\r\n * consumer's; the `InlineStatus`/`A11yCheck` stories carry the editorial contract. NO `ariaLabel`\r\n * input (ADR 033 boundary #8).\r\n *\r\n * **Look is skin-owned:** circle-vs-square is the `radius` comp token (brutal's `radius.full: 0`\r\n * ships a square dot automatically). The fill is the semantic `intent`→`sys.color.<intent>.base`\r\n * (recolour at the sys level, not a per-dot token — skin philosophy); NO `emphasis` (always filled),\r\n * NO `live` (a dot has no text to announce — the consumer's adjacent live text does), NO\r\n * `color`/`variant`/`shape` look-inputs.\r\n */\r\n@Component({\r\n selector: 'skra-status-dot',\r\n standalone: true,\r\n template: '',\r\n styleUrl: './status-dot.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var]).\r\n '[attr.data-skra-intent]': 'intent()',\r\n '[attr.data-skra-size]': 'size()',\r\n },\r\n})\r\nexport class SkraStatusDot {\r\n /** Variant Surface Intent axis (ADR 035) — the fill colour (status palette subset). */\r\n readonly intent = input<StatusDotIntent>('neutral');\r\n\r\n /** Variant Surface Size axis (ADR 035) — the dot's (colored core) diameter. */\r\n readonly size = input<StatusDotSize>('md');\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAcU,aAAa,CAAA;;IAEf,MAAM,GAAG,KAAK,CAAkB,SAAS;+EAAC;;IAG1C,IAAI,GAAG,KAAK,CAAgB,IAAI;6EAAC;uGAL/B,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,uaAVd,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,gvCAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAUD,aAAa,EAAA,UAAA,EAAA,CAAA;kBAbzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,EAAA,UAAA,EACf,IAAI,EAAA,QAAA,EACN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,yBAAyB,EAAE,UAAU;AACrC,wBAAA,uBAAuB,EAAE,QAAQ;AAClC,qBAAA,EAAA,MAAA,EAAA,CAAA,gvCAAA,CAAA,EAAA;;;ACzEH;;AAEG;;;;"}
|
|
@@ -67,10 +67,10 @@ class SkraSwitch {
|
|
|
67
67
|
event.preventDefault();
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
71
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraSwitch, isStandalone: true, selector: "input[type=\"checkbox\"][skraSwitch]", host: { attributes: { "role": "switch" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.data-skra-disabled": "context?.isDisabled() ? \"\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null" } }, ngImport: i0, template: '', isInline: true, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-background-readonly);border-color:var(--skra-comp-field-border-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
72
72
|
}
|
|
73
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
73
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, decorators: [{
|
|
74
74
|
type: Component,
|
|
75
75
|
args: [{ selector: 'input[type="checkbox"][skraSwitch]', standalone: true, template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
76
76
|
// The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * Wires a native `<input type=\"checkbox\">` to the **switch** role + skin when inside\n * `<skra-field>` (ADR 013), or standalone with no cascade. Per ADR 039/040, Forge ships\n * no `<skra-switch>` wrapper — this is a Component-on-the-native-host (`<input>` is void →\n * `template: ''`, ADR 040 §2) carrying its own `switch.scss` via Emulated encapsulation. The\n * ADR 039 revision history named this exact pattern as the future switch primitive.\n *\n * **The directive SETS `role=\"switch\"`** (it is not part of the selector) — the consumer must\n * not be asked to repeat an obvious, required ARIA role. No native HTML element produces switch\n * semantics, so `role=\"switch\"` is the legitimate ARIA mechanism (native-attr-first rule 2). The\n * browser maps the native checked state to `aria-checked` (on/off) under this role.\n *\n * <!-- inside Field -->\n * <skra-field>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * <label skraLabelFor>Enable notifications</label>\n * </skra-field>\n *\n * <!-- standalone (label wraps input — no id/for needed) -->\n * <label>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * Dark mode\n * </label>\n *\n * Value channel stays consumer-owned per ADR 037 (native `[checked]` + `(change)`, Reactive\n * Forms `formControlName`, Signal Forms `[formField]`, or `[(ngModel)]` — all orthogonal). Toggle\n * state is NOT reflected as `data-skra-*` (that would require Forge to observe native state,\n * violating ADR 037); the skin keys off the native `:checked` pseudo-class.\n *\n * Distinct from `skraCheckbox` (the atom-granularity split): a switch is strictly binary —\n * `role=\"switch\"` forbids `aria-checked=\"mixed\"`, so there is **no `indeterminate` input**.\n */\n@Component({\n selector: 'input[type=\"checkbox\"][skraSwitch]',\n standalone: true,\n // Void host — no <ng-content>. See ADR 040 §2.\n template: '',\n styleUrl: './switch.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).\n role: 'switch',\n '[attr.data-skra-disabled]': 'context?.isDisabled() ? \"\" : null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n // Readonly is ARIA-only (native `readonly` doesn't apply to checkboxes per HTML spec);\n // styling keys off `[aria-readonly]`. Mirrors skraCheckbox / skraRadio.\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '(click)': 'blockWhenReadonly($event)',\n '(keydown)': 'blockKeyWhenReadonly($event)',\n },\n})\nexport class SkraSwitch {\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n if (this.context) {\n const ctx = this.context;\n const el = this.el.nativeElement;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n }\n }\n\n /**\n * Readonly enforcement — native checkbox has no `[readonly]`, so without this the\n * `aria-readonly` we announce would be a lie (the user could still toggle it).\n * `preventDefault` on `click` blocks the toggle from both pointer and Space (keyboard\n * activation dispatches a click on form controls). Mirrors the checkbox/radio guards.\n */\n protected blockWhenReadonly(event: Event): void {\n if (this.context?.isReadonly()) event.preventDefault();\n }\n\n /** Block keyboard activation (Space) when readonly; let `Tab` through. */\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\n if (this.context?.isReadonly() && event.key !== 'Tab') {\n event.preventDefault();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,UAAU,CAAA;AACJ,IAAA,EAAE,GAAG,MAAM,CAA+B,UAAU,CAAC;IAC7D,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;AACxB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;YAChC,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACO,IAAA,iBAAiB,CAAC,KAAY,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IACxD;;AAGU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;AACjD,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;YACrD,KAAK,CAAC,cAAc,EAAE;QACxB;IACF;uGAlCW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2fAjBX,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,UAAU,EAAA,UAAA,EAAA,CAAA;kBArBtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,EAAA,UAAA,EAClC,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,2BAA2B,EAAE,mCAAmC;AAChE,wBAAA,qBAAqB,EAAE,qCAAqC;;;AAG5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n effect,\r\n inject,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '@skra/ui/field';\r\n\r\n/**\r\n * Wires a native `<input type=\"checkbox\">` to the **switch** role + skin when inside\r\n * `<skra-field>` (ADR 013), or standalone with no cascade. Per ADR 039/040, Forge ships\r\n * no `<skra-switch>` wrapper — this is a Component-on-the-native-host (`<input>` is void →\r\n * `template: ''`, ADR 040 §2) carrying its own `switch.scss` via Emulated encapsulation. The\r\n * ADR 039 revision history named this exact pattern as the future switch primitive.\r\n *\r\n * **The directive SETS `role=\"switch\"`** (it is not part of the selector) — the consumer must\r\n * not be asked to repeat an obvious, required ARIA role. No native HTML element produces switch\r\n * semantics, so `role=\"switch\"` is the legitimate ARIA mechanism (native-attr-first rule 2). The\r\n * browser maps the native checked state to `aria-checked` (on/off) under this role.\r\n *\r\n * <!-- inside Field -->\r\n * <skra-field>\r\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\r\n * <label skraLabelFor>Enable notifications</label>\r\n * </skra-field>\r\n *\r\n * <!-- standalone (label wraps input — no id/for needed) -->\r\n * <label>\r\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\r\n * Dark mode\r\n * </label>\r\n *\r\n * Value channel stays consumer-owned per ADR 037 (native `[checked]` + `(change)`, Reactive\r\n * Forms `formControlName`, Signal Forms `[formField]`, or `[(ngModel)]` — all orthogonal). Toggle\r\n * state is NOT reflected as `data-skra-*` (that would require Forge to observe native state,\r\n * violating ADR 037); the skin keys off the native `:checked` pseudo-class.\r\n *\r\n * Distinct from `skraCheckbox` (the atom-granularity split): a switch is strictly binary —\r\n * `role=\"switch\"` forbids `aria-checked=\"mixed\"`, so there is **no `indeterminate` input**.\r\n */\r\n@Component({\r\n selector: 'input[type=\"checkbox\"][skraSwitch]',\r\n standalone: true,\r\n // Void host — no <ng-content>. See ADR 040 §2.\r\n template: '',\r\n styleUrl: './switch.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).\r\n role: 'switch',\r\n '[attr.data-skra-disabled]': 'context?.isDisabled() ? \"\" : null',\r\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\r\n // Readonly is ARIA-only (native `readonly` doesn't apply to checkboxes per HTML spec);\r\n // styling keys off `[aria-readonly]`. Mirrors skraCheckbox / skraRadio.\r\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\r\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\r\n '(click)': 'blockWhenReadonly($event)',\r\n '(keydown)': 'blockKeyWhenReadonly($event)',\r\n },\r\n})\r\nexport class SkraSwitch {\r\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\r\n readonly context = inject(SkraFieldContext, { optional: true });\r\n\r\n constructor() {\r\n // Field-cascaded native properties — only bind when context is present so\r\n // standalone consumers retain full control of their static attributes.\r\n if (this.context) {\r\n const ctx = this.context;\r\n const el = this.el.nativeElement;\r\n effect(() => {\r\n el.id = ctx.fieldId();\r\n });\r\n effect(() => {\r\n el.disabled = ctx.isDisabled();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Readonly enforcement — native checkbox has no `[readonly]`, so without this the\r\n * `aria-readonly` we announce would be a lie (the user could still toggle it).\r\n * `preventDefault` on `click` blocks the toggle from both pointer and Space (keyboard\r\n * activation dispatches a click on form controls). Mirrors the checkbox/radio guards.\r\n */\r\n protected blockWhenReadonly(event: Event): void {\r\n if (this.context?.isReadonly()) event.preventDefault();\r\n }\r\n\r\n /** Block keyboard activation (Space) when readonly; let `Tab` through. */\r\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\r\n if (this.context?.isReadonly() && event.key !== 'Tab') {\r\n event.preventDefault();\r\n }\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,UAAU,CAAA;AACJ,IAAA,EAAE,GAAG,MAAM,CAA+B,UAAU,CAAC;IAC7D,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;AACxB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;YAChC,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACO,IAAA,iBAAiB,CAAC,KAAY,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IACxD;;AAGU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;AACjD,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;YACrD,KAAK,CAAC,cAAc,EAAE;QACxB;IACF;uGAlCW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2fAjBX,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,UAAU,EAAA,UAAA,EAAA,CAAA;kBArBtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,EAAA,UAAA,EAClC,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,2BAA2B,EAAE,mCAAmC;AAChE,wBAAA,qBAAqB,EAAE,qCAAqC;;;AAG5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
|
|
@@ -22,11 +22,14 @@ class SkraTabsContext {
|
|
|
22
22
|
/** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */
|
|
23
23
|
baseId = `skra-tabs-${++tabsInstanceCounter}`;
|
|
24
24
|
/** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */
|
|
25
|
-
selected = signal('',
|
|
25
|
+
selected = signal('', /* @ts-ignore */
|
|
26
|
+
...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
26
27
|
/** Roving-focus position — the value of the tab that currently carries `tabindex="0"` (read-only to children). */
|
|
27
|
-
activeValue = signal('',
|
|
28
|
+
activeValue = signal('', /* @ts-ignore */
|
|
29
|
+
...(ngDevMode ? [{ debugName: "activeValue" }] : /* istanbul ignore next */ []));
|
|
28
30
|
/** Activation model (read-only to children). */
|
|
29
|
-
activation = signal('automatic',
|
|
31
|
+
activation = signal('automatic', /* @ts-ignore */
|
|
32
|
+
...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
|
|
30
33
|
tabId(value) {
|
|
31
34
|
return `${this.baseId}-tab-${idSafe(value)}`;
|
|
32
35
|
}
|
|
@@ -40,10 +43,10 @@ class SkraTabsContext {
|
|
|
40
43
|
select = () => undefined;
|
|
41
44
|
/** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */
|
|
42
45
|
handleKeydown = () => undefined;
|
|
43
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
44
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
47
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext });
|
|
45
48
|
}
|
|
46
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext, decorators: [{
|
|
47
50
|
type: Injectable
|
|
48
51
|
}] });
|
|
49
52
|
|
|
@@ -63,17 +66,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
63
66
|
*/
|
|
64
67
|
class SkraTab {
|
|
65
68
|
/** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */
|
|
66
|
-
value = input.required(
|
|
69
|
+
value = input.required(/* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
67
71
|
host = inject(ElementRef);
|
|
68
72
|
ctx = inject(SkraTabsContext, { optional: true });
|
|
69
|
-
tabId = computed(() => this.ctx?.tabId(this.value()) ?? null,
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, /* @ts-ignore */
|
|
74
|
+
...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
|
|
75
|
+
panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, /* @ts-ignore */
|
|
76
|
+
...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
|
|
77
|
+
ariaSelected = computed(() => this.ctx?.isSelected(this.value()) ? 'true' : 'false', /* @ts-ignore */
|
|
78
|
+
...(ngDevMode ? [{ debugName: "ariaSelected" }] : /* istanbul ignore next */ []));
|
|
72
79
|
tabindex = computed(() => {
|
|
73
80
|
if (!this.ctx)
|
|
74
81
|
return null; // standalone misuse — leave the native button focusable
|
|
75
82
|
return this.ctx.activeValue() === this.value() ? '0' : '-1';
|
|
76
|
-
},
|
|
83
|
+
}, /* @ts-ignore */
|
|
84
|
+
...(ngDevMode ? [{ debugName: "tabindex" }] : /* istanbul ignore next */ []));
|
|
77
85
|
constructor() {
|
|
78
86
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
79
87
|
if (!this.ctx) {
|
|
@@ -98,10 +106,10 @@ class SkraTab {
|
|
|
98
106
|
return; // belt-and-suspenders (native disabled won't fire click)
|
|
99
107
|
this.ctx?.select(this.value());
|
|
100
108
|
}
|
|
101
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
102
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
109
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
110
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTab, isStandalone: true, selector: "button[skraTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "tabId()", "attr.aria-controls": "panelId()", "attr.aria-selected": "ariaSelected()", "attr.tabindex": "tabindex()" } }, exportAs: ["skraTab"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
103
111
|
}
|
|
104
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
112
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, decorators: [{
|
|
105
113
|
type: Component,
|
|
106
114
|
args: [{ selector: 'button[skraTab]', standalone: true, exportAs: 'skraTab', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
107
115
|
role: 'tab',
|
|
@@ -123,12 +131,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
123
131
|
*/
|
|
124
132
|
class SkraTabPanel {
|
|
125
133
|
/** Selection key — matched against the owning `button[skraTab]`'s `value`. */
|
|
126
|
-
value = input.required(
|
|
134
|
+
value = input.required(/* @ts-ignore */
|
|
135
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
127
136
|
ctx = inject(SkraTabsContext, { optional: true });
|
|
128
|
-
panelId = computed(() => this.ctx?.panelId(this.value()) ?? null,
|
|
129
|
-
|
|
137
|
+
panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, /* @ts-ignore */
|
|
138
|
+
...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
|
|
139
|
+
tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, /* @ts-ignore */
|
|
140
|
+
...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
|
|
130
141
|
/** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */
|
|
131
|
-
hidden = computed(() => this.ctx?.isSelected(this.value()) ? null : '',
|
|
142
|
+
hidden = computed(() => this.ctx?.isSelected(this.value()) ? null : '', /* @ts-ignore */
|
|
143
|
+
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
132
144
|
constructor() {
|
|
133
145
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
134
146
|
if (!this.ctx) {
|
|
@@ -137,10 +149,10 @@ class SkraTabPanel {
|
|
|
137
149
|
}
|
|
138
150
|
}
|
|
139
151
|
}
|
|
140
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
141
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
152
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
153
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTabPanel, isStandalone: true, selector: "[skraTabPanel]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tabpanel", "tabindex": "0" }, properties: { "attr.id": "panelId()", "attr.aria-labelledby": "tabId()", "attr.hidden": "hidden()" } }, exportAs: ["skraTabPanel"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:block;margin:0;box-sizing:border-box;padding-block:var(--skra-comp-tabs-panel-padding-block);padding-inline:var(--skra-comp-tabs-panel-padding-inline)}:host([hidden]){display:none}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
142
154
|
}
|
|
143
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
155
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabPanel, decorators: [{
|
|
144
156
|
type: Component,
|
|
145
157
|
args: [{ selector: '[skraTabPanel]', standalone: true, exportAs: 'skraTabPanel', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
146
158
|
role: 'tabpanel',
|
|
@@ -232,9 +244,11 @@ class SkraTabsKeyboard {
|
|
|
232
244
|
*/
|
|
233
245
|
class SkraTabs {
|
|
234
246
|
/** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */
|
|
235
|
-
selected = input('',
|
|
247
|
+
selected = input('', /* @ts-ignore */
|
|
248
|
+
...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
236
249
|
/** Automatic (selection follows roving focus) | manual (Enter/Space selects). */
|
|
237
|
-
activation = input('automatic',
|
|
250
|
+
activation = input('automatic', /* @ts-ignore */
|
|
251
|
+
...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
|
|
238
252
|
/** Fires ONLY on user activation — never on a programmatic `[selected]` change. */
|
|
239
253
|
selectedChange = output();
|
|
240
254
|
ctx = inject(SkraTabsContext);
|
|
@@ -302,10 +316,10 @@ class SkraTabs {
|
|
|
302
316
|
console.warn(`[skraTabs] panel value="${v}" has no matching button[skraTab] — it will never be revealed.`);
|
|
303
317
|
}
|
|
304
318
|
}
|
|
305
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
306
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
319
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
320
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.1", type: SkraTabs, isStandalone: true, selector: "[skraTabs]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, activation: { classPropertyName: "activation", publicName: "activation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange" }, providers: [SkraTabsContext], queries: [{ propertyName: "tabs", predicate: SkraTab, descendants: true, isSignal: true }, { propertyName: "panels", predicate: SkraTabPanel, descendants: true, isSignal: true }], exportAs: ["skraTabs"], ngImport: i0 });
|
|
307
321
|
}
|
|
308
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
322
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabs, decorators: [{
|
|
309
323
|
type: Directive,
|
|
310
324
|
args: [{
|
|
311
325
|
selector: '[skraTabs]',
|
|
@@ -336,10 +350,10 @@ class SkraTablist {
|
|
|
336
350
|
onKeydown(event) {
|
|
337
351
|
this.ctx?.handleKeydown(event);
|
|
338
352
|
}
|
|
339
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
340
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
353
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTablist, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
354
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraTablist, isStandalone: true, selector: "[skraTablist]", host: { attributes: { "role": "tablist", "aria-orientation": "horizontal" }, listeners: { "keydown": "onKeydown($event)" } }, exportAs: ["skraTablist"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;gap:var(--skra-comp-tabs-gap);margin:0;box-sizing:border-box;border-block-end:var(--skra-comp-tabs-tablist-border-width) solid var(--skra-comp-tabs-tablist-border-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
341
355
|
}
|
|
342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTablist, decorators: [{
|
|
343
357
|
type: Component,
|
|
344
358
|
args: [{ selector: '[skraTablist]', standalone: true, exportAs: 'skraTablist', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
345
359
|
role: 'tablist',
|