@akcelik/strct 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1890,7 +1890,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
1890
1890
  }, styles: [".strct-av{position:relative;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;flex-shrink:0;background:var(--bg-3);color:var(--t1);overflow:visible;font-size:13px;font-weight:600;-webkit-user-select:none;user-select:none;border:1px solid var(--b2)}.strct-av--sm{width:26px;height:26px;font-size:12px}.strct-av--lg{width:48px;height:48px;font-size:17px}.strct-av__img{width:100%;height:100%;border-radius:50%;object-fit:cover}.strct-av__initials{line-height:1}.strct-av__status{position:absolute;inset-inline-end:-1px;bottom:-1px;width:30%;height:30%;min-width:8px;min-height:8px;border-radius:50%;border:2px solid var(--bg-1);background:var(--t3)}.strct-av--online .strct-av__status{background:var(--success)}.strct-av--busy .strct-av__status{background:var(--critical)}.strct-av--offline .strct-av__status{background:var(--t3)}\n"] }]
1891
1891
  }], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }] } });
1892
1892
 
1893
- /** Horizontal value/usage bar. `<strct-progress [value]="72" status="warning" />`. */
1893
+ /**
1894
+ * Horizontal value/usage bar. `<strct-progress [value]="72" status="warning" />`.
1895
+ *
1896
+ * **Meter mode.** A capacity bar says what it measures and how much, next to
1897
+ * the bar: `visibleLabel` puts `label` at the start of a row above the track,
1898
+ * `showValue` puts `valueText` (default `${value}%`) at its end, and `caption`
1899
+ * adds a quiet line under it. `segments` stacks more than one fill, and
1900
+ * `indeterminate` is a task that is running but reports no percentage. Every
1901
+ * one of these is off by default, so a plain bar renders exactly as before.
1902
+ */
1894
1903
  class StrctProgress {
1895
1904
  /** Current value. */
1896
1905
  value = input(0, /* @ts-ignore */
@@ -1901,6 +1910,21 @@ class StrctProgress {
1901
1910
  /** Visual status color. */
1902
1911
  status = input('accent', /* @ts-ignore */
1903
1912
  ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
1913
+ /** Show `label` above the bar as well as announcing it. */
1914
+ visibleLabel = input(false, { ...(ngDevMode ? { debugName: "visibleLabel" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1915
+ /** Show the value at the end of the row above the bar. */
1916
+ showValue = input(false, { ...(ngDevMode ? { debugName: "showValue" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1917
+ /** What `showValue` prints — "293 GB of 512 GB". Defaults to `${value}%`. */
1918
+ valueText = input('', /* @ts-ignore */
1919
+ ...(ngDevMode ? [{ debugName: "valueText" }] : /* istanbul ignore next */ []));
1920
+ /** A quiet line under the bar — "219 GB free across 2 nodes". */
1921
+ caption = input('', /* @ts-ignore */
1922
+ ...(ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []));
1923
+ /** Running, but with no percentage to report. */
1924
+ indeterminate = input(false, { ...(ngDevMode ? { debugName: "indeterminate" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1925
+ /** Stack several fills (used now + what would arrive); clamped to 100 total. */
1926
+ segments = input(null, /* @ts-ignore */
1927
+ ...(ngDevMode ? [{ debugName: "segments" }] : /* istanbul ignore next */ []));
1904
1928
  /**
1905
1929
  * Optional value-driven thresholds. When set, the component picks its own
1906
1930
  * status from the value instead of the caller computing it: `value >= critical`
@@ -1912,6 +1936,30 @@ class StrctProgress {
1912
1936
  ...(ngDevMode ? [{ debugName: "thresholds" }] : /* istanbul ignore next */ []));
1913
1937
  clamped = computed(() => Math.max(0, Math.min(100, this.value())), /* @ts-ignore */
1914
1938
  ...(ngDevMode ? [{ debugName: "clamped" }] : /* istanbul ignore next */ []));
1939
+ /** Segments as widths that together never exceed the track. */
1940
+ stacked = computed(() => {
1941
+ const segments = this.segments();
1942
+ if (!segments?.length)
1943
+ return null;
1944
+ let left = 100;
1945
+ return segments.map((s) => {
1946
+ const width = Math.max(0, Math.min(s.value, left));
1947
+ left -= width;
1948
+ return { width, status: s.status ?? this.resolvedStatus() };
1949
+ });
1950
+ }, /* @ts-ignore */
1951
+ ...(ngDevMode ? [{ debugName: "stacked" }] : /* istanbul ignore next */ []));
1952
+ /** What a screen reader reads instead of the bare number. */
1953
+ valueDescription = computed(() => {
1954
+ if (this.indeterminate())
1955
+ return 'In progress';
1956
+ const segments = this.segments();
1957
+ if (segments?.length) {
1958
+ return segments.map((s) => `${s.label ? s.label + ' ' : ''}${s.value}%`).join(', ');
1959
+ }
1960
+ return this.valueText() || null;
1961
+ }, /* @ts-ignore */
1962
+ ...(ngDevMode ? [{ debugName: "valueDescription" }] : /* istanbul ignore next */ []));
1915
1963
  /** Status after applying thresholds (falls back to `status` when none set). */
1916
1964
  resolvedStatus = computed(() => {
1917
1965
  const t = this.thresholds();
@@ -1927,39 +1975,90 @@ class StrctProgress {
1927
1975
  }, /* @ts-ignore */
1928
1976
  ...(ngDevMode ? [{ debugName: "resolvedStatus" }] : /* istanbul ignore next */ []));
1929
1977
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctProgress, deps: [], target: i0.ɵɵFactoryTarget.Component });
1930
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctProgress, isStandalone: true, selector: "strct-progress", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, thresholds: { classPropertyName: "thresholds", publicName: "thresholds", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-progress--success": "resolvedStatus() === 'success'", "class.strct-progress--warning": "resolvedStatus() === 'warning'", "class.strct-progress--critical": "resolvedStatus() === 'critical'" }, classAttribute: "strct-progress" }, ngImport: i0, template: `
1978
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctProgress, isStandalone: true, selector: "strct-progress", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, visibleLabel: { classPropertyName: "visibleLabel", publicName: "visibleLabel", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, valueText: { classPropertyName: "valueText", publicName: "valueText", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, segments: { classPropertyName: "segments", publicName: "segments", isSignal: true, isRequired: false, transformFunction: null }, thresholds: { classPropertyName: "thresholds", publicName: "thresholds", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-progress--neutral": "resolvedStatus() === 'neutral'", "class.strct-progress--success": "resolvedStatus() === 'success'", "class.strct-progress--warning": "resolvedStatus() === 'warning'", "class.strct-progress--critical": "resolvedStatus() === 'critical'" }, classAttribute: "strct-progress" }, ngImport: i0, template: `
1979
+ @if (visibleLabel() || showValue()) {
1980
+ <div class="strct-progress__row">
1981
+ @if (visibleLabel()) {
1982
+ <span class="strct-progress__label">{{ label() }}</span>
1983
+ }
1984
+ @if (showValue()) {
1985
+ <span class="strct-progress__value">{{ valueText() || clamped() + '%' }}</span>
1986
+ }
1987
+ </div>
1988
+ }
1931
1989
  <div
1932
1990
  class="strct-progress__track"
1933
1991
  role="progressbar"
1934
1992
  [attr.aria-label]="label() || 'Progress'"
1935
- [attr.aria-valuenow]="clamped()"
1936
- aria-valuemin="0"
1937
- aria-valuemax="100"
1993
+ [attr.aria-valuenow]="indeterminate() ? null : clamped()"
1994
+ [attr.aria-valuetext]="valueDescription()"
1995
+ [attr.aria-valuemin]="indeterminate() ? null : 0"
1996
+ [attr.aria-valuemax]="indeterminate() ? null : 100"
1938
1997
  >
1939
- <div class="strct-progress__fill" [style.width.%]="clamped()"></div>
1998
+ @if (indeterminate()) {
1999
+ <div class="strct-progress__fill strct-progress__fill--indeterminate"></div>
2000
+ } @else if (stacked(); as parts) {
2001
+ @for (part of parts; track $index) {
2002
+ <div
2003
+ class="strct-progress__fill strct-progress__fill--{{ part.status }}"
2004
+ [style.width.%]="part.width"
2005
+ ></div>
2006
+ }
2007
+ } @else {
2008
+ <div class="strct-progress__fill" [style.width.%]="clamped()"></div>
2009
+ }
1940
2010
  </div>
1941
- `, isInline: true, styles: [".strct-progress{display:block}.strct-progress__track{height:6px;border-radius:var(--radius-sm);background:var(--strct-progress-track, color-mix(in srgb, var(--t1) 12%, transparent));box-shadow:inset 0 0 0 1px var(--b2);overflow:hidden}.strct-progress__fill{height:100%;border-radius:var(--radius-sm);background:var(--acc);transition:width .3s ease}.strct-progress--success .strct-progress__fill{background:var(--success)}.strct-progress--warning .strct-progress__fill{background:var(--warning)}.strct-progress--critical .strct-progress__fill{background:var(--critical)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2011
+ @if (caption()) {
2012
+ <p class="strct-progress__caption">{{ caption() }}</p>
2013
+ }
2014
+ `, isInline: true, styles: [".strct-progress{display:block}.strct-progress__row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2);margin-block-end:4px;font-size:var(--text-sm)}.strct-progress__label{color:var(--t2);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-progress__value{color:var(--t1);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-progress__caption{margin:4px 0 0;font-size:var(--text-sm);line-height:1.5;color:var(--t3)}.strct-progress__track{position:relative;display:flex;height:6px;border-radius:var(--radius-sm);background:var(--strct-progress-track, color-mix(in srgb, var(--t1) 12%, transparent));box-shadow:inset 0 0 0 1px var(--b2);overflow:hidden}.strct-progress__fill{height:100%;border-radius:var(--radius-sm);background:var(--acc);transition:width .3s ease}.strct-progress--neutral .strct-progress__fill{background:var(--t3)}.strct-progress--success .strct-progress__fill{background:var(--success)}.strct-progress--warning .strct-progress__fill{background:var(--warning)}.strct-progress--critical .strct-progress__fill{background:var(--critical)}.strct-progress .strct-progress__fill--neutral{background:var(--t3)}.strct-progress .strct-progress__fill--accent{background:var(--acc)}.strct-progress .strct-progress__fill--success{background:var(--success)}.strct-progress .strct-progress__fill--warning{background:var(--warning)}.strct-progress .strct-progress__fill--critical{background:var(--critical)}.strct-progress__track .strct-progress__fill+.strct-progress__fill{border-start-start-radius:0;border-end-start-radius:0}.strct-progress .strct-progress__fill--indeterminate{width:35%;animation:strct-progress-sweep 1.1s ease-in-out infinite}@keyframes strct-progress-sweep{0%{transform:translate(-120%)}to{transform:translate(340%)}}@media(prefers-reduced-motion:reduce){.strct-progress .strct-progress__fill--indeterminate{width:100%;animation:none;background:repeating-linear-gradient(135deg,var(--acc) 0 6px,color-mix(in srgb,var(--acc) 45%,transparent) 6px 12px)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1942
2015
  }
1943
2016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctProgress, decorators: [{
1944
2017
  type: Component,
1945
2018
  args: [{ selector: 'strct-progress', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
2019
+ @if (visibleLabel() || showValue()) {
2020
+ <div class="strct-progress__row">
2021
+ @if (visibleLabel()) {
2022
+ <span class="strct-progress__label">{{ label() }}</span>
2023
+ }
2024
+ @if (showValue()) {
2025
+ <span class="strct-progress__value">{{ valueText() || clamped() + '%' }}</span>
2026
+ }
2027
+ </div>
2028
+ }
1946
2029
  <div
1947
2030
  class="strct-progress__track"
1948
2031
  role="progressbar"
1949
2032
  [attr.aria-label]="label() || 'Progress'"
1950
- [attr.aria-valuenow]="clamped()"
1951
- aria-valuemin="0"
1952
- aria-valuemax="100"
2033
+ [attr.aria-valuenow]="indeterminate() ? null : clamped()"
2034
+ [attr.aria-valuetext]="valueDescription()"
2035
+ [attr.aria-valuemin]="indeterminate() ? null : 0"
2036
+ [attr.aria-valuemax]="indeterminate() ? null : 100"
1953
2037
  >
1954
- <div class="strct-progress__fill" [style.width.%]="clamped()"></div>
2038
+ @if (indeterminate()) {
2039
+ <div class="strct-progress__fill strct-progress__fill--indeterminate"></div>
2040
+ } @else if (stacked(); as parts) {
2041
+ @for (part of parts; track $index) {
2042
+ <div
2043
+ class="strct-progress__fill strct-progress__fill--{{ part.status }}"
2044
+ [style.width.%]="part.width"
2045
+ ></div>
2046
+ }
2047
+ } @else {
2048
+ <div class="strct-progress__fill" [style.width.%]="clamped()"></div>
2049
+ }
1955
2050
  </div>
2051
+ @if (caption()) {
2052
+ <p class="strct-progress__caption">{{ caption() }}</p>
2053
+ }
1956
2054
  `, host: {
1957
2055
  class: 'strct-progress',
2056
+ '[class.strct-progress--neutral]': "resolvedStatus() === 'neutral'",
1958
2057
  '[class.strct-progress--success]': "resolvedStatus() === 'success'",
1959
2058
  '[class.strct-progress--warning]': "resolvedStatus() === 'warning'",
1960
2059
  '[class.strct-progress--critical]': "resolvedStatus() === 'critical'",
1961
- }, styles: [".strct-progress{display:block}.strct-progress__track{height:6px;border-radius:var(--radius-sm);background:var(--strct-progress-track, color-mix(in srgb, var(--t1) 12%, transparent));box-shadow:inset 0 0 0 1px var(--b2);overflow:hidden}.strct-progress__fill{height:100%;border-radius:var(--radius-sm);background:var(--acc);transition:width .3s ease}.strct-progress--success .strct-progress__fill{background:var(--success)}.strct-progress--warning .strct-progress__fill{background:var(--warning)}.strct-progress--critical .strct-progress__fill{background:var(--critical)}\n"] }]
1962
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], thresholds: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholds", required: false }] }] } });
2060
+ }, styles: [".strct-progress{display:block}.strct-progress__row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2);margin-block-end:4px;font-size:var(--text-sm)}.strct-progress__label{color:var(--t2);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-progress__value{color:var(--t1);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-progress__caption{margin:4px 0 0;font-size:var(--text-sm);line-height:1.5;color:var(--t3)}.strct-progress__track{position:relative;display:flex;height:6px;border-radius:var(--radius-sm);background:var(--strct-progress-track, color-mix(in srgb, var(--t1) 12%, transparent));box-shadow:inset 0 0 0 1px var(--b2);overflow:hidden}.strct-progress__fill{height:100%;border-radius:var(--radius-sm);background:var(--acc);transition:width .3s ease}.strct-progress--neutral .strct-progress__fill{background:var(--t3)}.strct-progress--success .strct-progress__fill{background:var(--success)}.strct-progress--warning .strct-progress__fill{background:var(--warning)}.strct-progress--critical .strct-progress__fill{background:var(--critical)}.strct-progress .strct-progress__fill--neutral{background:var(--t3)}.strct-progress .strct-progress__fill--accent{background:var(--acc)}.strct-progress .strct-progress__fill--success{background:var(--success)}.strct-progress .strct-progress__fill--warning{background:var(--warning)}.strct-progress .strct-progress__fill--critical{background:var(--critical)}.strct-progress__track .strct-progress__fill+.strct-progress__fill{border-start-start-radius:0;border-end-start-radius:0}.strct-progress .strct-progress__fill--indeterminate{width:35%;animation:strct-progress-sweep 1.1s ease-in-out infinite}@keyframes strct-progress-sweep{0%{transform:translate(-120%)}to{transform:translate(340%)}}@media(prefers-reduced-motion:reduce){.strct-progress .strct-progress__fill--indeterminate{width:100%;animation:none;background:repeating-linear-gradient(135deg,var(--acc) 0 6px,color-mix(in srgb,var(--acc) 45%,transparent) 6px 12px)}}\n"] }]
2061
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], visibleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleLabel", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], valueText: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueText", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], segments: [{ type: i0.Input, args: [{ isSignal: true, alias: "segments", required: false }] }], thresholds: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholds", required: false }] }] } });
1963
2062
 
1964
2063
  /** Indeterminate loading ring. `<strct-spinner size="sm" />`. */
1965
2064
  class StrctSpinner {
@@ -1969,19 +2068,37 @@ class StrctSpinner {
1969
2068
  /** Accessible label (localizable). */
1970
2069
  label = input('Loading', /* @ts-ignore */
1971
2070
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2071
+ /**
2072
+ * Visible text beside the ring — "Reading…". It becomes the accessible name
2073
+ * too, so the spinner is not announced as "Loading" while it says something
2074
+ * else on screen.
2075
+ */
2076
+ caption = input('', /* @ts-ignore */
2077
+ ...(ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []));
1972
2078
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctSpinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
1973
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctSpinner, isStandalone: true, selector: "strct-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar" }, properties: { "attr.aria-label": "label()", "class.strct-spinner--sm": "size() === 'sm'", "class.strct-spinner--lg": "size() === 'lg'" }, classAttribute: "strct-spinner" }, ngImport: i0, template: '', isInline: true, styles: [".strct-spinner{display:inline-block;width:22px;height:22px;border:2.5px solid var(--b3);border-top-color:var(--acc);border-radius:50%;animation:strct-spin .7s linear infinite}.strct-spinner--sm{width:14px;height:14px;border-width:2px}.strct-spinner--lg{width:34px;height:34px;border-width:3px}@keyframes strct-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.strct-spinner{animation-duration:1.6s}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2079
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctSpinner, isStandalone: true, selector: "strct-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar" }, properties: { "class.strct-spinner--captioned": "caption()", "attr.aria-label": "caption() || label()", "class.strct-spinner--sm": "size() === 'sm'", "class.strct-spinner--lg": "size() === 'lg'" }, classAttribute: "strct-spinner" }, ngImport: i0, template: `
2080
+ @if (caption()) {
2081
+ <span class="strct-spinner__ring"></span>
2082
+ <span class="strct-spinner__caption">{{ caption() }}</span>
2083
+ }
2084
+ `, isInline: true, styles: [".strct-spinner{display:inline-block;width:22px;height:22px;border:2.5px solid var(--b3);border-top-color:var(--acc);border-radius:50%;animation:strct-spin .7s linear infinite}.strct-spinner--sm{width:14px;height:14px;border-width:2px}.strct-spinner--lg{width:34px;height:34px;border-width:3px}@keyframes strct-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.strct-spinner{animation-duration:1.6s}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1974
2085
  }
1975
2086
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctSpinner, decorators: [{
1976
2087
  type: Component,
1977
- args: [{ selector: 'strct-spinner', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', host: {
2088
+ args: [{ selector: 'strct-spinner', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
2089
+ @if (caption()) {
2090
+ <span class="strct-spinner__ring"></span>
2091
+ <span class="strct-spinner__caption">{{ caption() }}</span>
2092
+ }
2093
+ `, host: {
1978
2094
  class: 'strct-spinner',
1979
2095
  role: 'progressbar',
1980
- '[attr.aria-label]': 'label()',
2096
+ '[class.strct-spinner--captioned]': 'caption()',
2097
+ '[attr.aria-label]': 'caption() || label()',
1981
2098
  '[class.strct-spinner--sm]': "size() === 'sm'",
1982
2099
  '[class.strct-spinner--lg]': "size() === 'lg'",
1983
2100
  }, styles: [".strct-spinner{display:inline-block;width:22px;height:22px;border:2.5px solid var(--b3);border-top-color:var(--acc);border-radius:50%;animation:strct-spin .7s linear infinite}.strct-spinner--sm{width:14px;height:14px;border-width:2px}.strct-spinner--lg{width:34px;height:34px;border-width:3px}@keyframes strct-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.strct-spinner{animation-duration:1.6s}}\n"] }]
1984
- }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
2101
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }] } });
1985
2102
 
1986
2103
  /**
1987
2104
  * Shimmering loading placeholder.
@@ -7134,7 +7251,7 @@ class StrctCellStatus {
7134
7251
  }
7135
7252
  </span>
7136
7253
  }
7137
- `, isInline: true, styles: [".strct-vstate{display:inline-flex;align-items:center;gap:var(--space-1);font-size:var(--text-sm);line-height:1;color:var(--t3)}.strct-vstate strct-icon{flex-shrink:0}.strct-vstate--ok{color:var(--success)}.strct-vstate--warning{color:var(--warning)}.strct-vstate--error{color:var(--critical)}.strct-vstate__msg{color:var(--t2)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7254
+ `, isInline: true, styles: [".strct-vstate{display:inline-flex;align-items:center;gap:var(--space-1);font-size:var(--text-sm);line-height:1;color:var(--t3)}.strct-vstate strct-icon{flex-shrink:0}.strct-vstate--ok{color:var(--success)}.strct-vstate--warning{color:var(--warning)}.strct-vstate--error{color:var(--critical)}.strct-vstate__msg{color:var(--t2)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7138
7255
  }
7139
7256
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctCellStatus, decorators: [{
7140
7257
  type: Component,
@@ -7287,7 +7404,7 @@ class StrctField {
7287
7404
  } @else if (hint()) {
7288
7405
  <div class="strct-field__msg strct-field__msg--hint" [id]="hintId">{{ hint() }}</div>
7289
7406
  }
7290
- `, isInline: true, styles: [".strct-field{display:flex;flex-direction:column;gap:6px}.strct-field__label{font-size:12px;font-weight:600;color:var(--t2)}.strct-field__req{color:var(--critical);margin-inline-start:2px}.strct-field__control{position:relative;display:flex;flex-direction:column}.strct-field__adorn{position:absolute;top:50%;inset-inline-end:10px;transform:translateY(-50%);display:inline-flex;align-items:center;pointer-events:none}.strct-field__adorn--ok{color:var(--success)}.strct-field__adorn--warning{color:var(--warning)}.strct-field__adorn--error{color:var(--critical)}.strct-field--validating .strct-control{padding-inline-end:32px}.strct-field__msg{font-size:12px;line-height:1.4}.strct-field__msg--hint,.strct-field__msg--checking{color:var(--t3)}.strct-field__msg--ok{color:var(--success)}.strct-field__msg--warning{color:var(--warning)}.strct-field__msg--error{color:var(--critical)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7407
+ `, isInline: true, styles: [".strct-field{display:flex;flex-direction:column;gap:6px}.strct-field__label{font-size:12px;font-weight:600;color:var(--t2)}.strct-field__req{color:var(--critical);margin-inline-start:2px}.strct-field__control{position:relative;display:flex;flex-direction:column}.strct-field__adorn{position:absolute;top:50%;inset-inline-end:10px;transform:translateY(-50%);display:inline-flex;align-items:center;pointer-events:none}.strct-field__adorn--ok{color:var(--success)}.strct-field__adorn--warning{color:var(--warning)}.strct-field__adorn--error{color:var(--critical)}.strct-field--validating .strct-control{padding-inline-end:32px}.strct-field__msg{font-size:12px;line-height:1.4}.strct-field__msg--hint,.strct-field__msg--checking{color:var(--t3)}.strct-field__msg--ok{color:var(--success)}.strct-field__msg--warning{color:var(--warning)}.strct-field__msg--error{color:var(--critical)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7291
7408
  }
7292
7409
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctField, decorators: [{
7293
7410
  type: Component,
@@ -17299,6 +17416,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
17299
17416
 
17300
17417
  const VARIANTS = {
17301
17418
  empty: { icon: 'folder', tone: 'neutral' },
17419
+ loading: { icon: '', tone: 'neutral' },
17302
17420
  denied: { icon: 'lock', tone: 'warning' },
17303
17421
  error: { icon: 'warning', tone: 'critical' },
17304
17422
  notfound: { icon: 'search', tone: 'neutral' },
@@ -17324,6 +17442,12 @@ class StrctEmptyState {
17324
17442
  ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
17325
17443
  title = input.required(/* @ts-ignore */
17326
17444
  ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
17445
+ /**
17446
+ * `sm` is the inline row a 240px frame wants: a 16px icon with the title and
17447
+ * description on one line. A page-sized empty state stays `md`.
17448
+ */
17449
+ size = input('md', /* @ts-ignore */
17450
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
17327
17451
  description = input('', /* @ts-ignore */
17328
17452
  ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
17329
17453
  resolvedIcon = computed(() => this.icon() || VARIANTS[this.variant()].icon, /* @ts-ignore */
@@ -17331,30 +17455,50 @@ class StrctEmptyState {
17331
17455
  toneClass = computed(() => this.tone() || VARIANTS[this.variant()].tone, /* @ts-ignore */
17332
17456
  ...(ngDevMode ? [{ debugName: "toneClass" }] : /* istanbul ignore next */ []));
17333
17457
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctEmptyState, deps: [], target: i0.ɵɵFactoryTarget.Component });
17334
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctEmptyState, isStandalone: true, selector: "strct-empty-state", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "strct-empty" }, ngImport: i0, template: `
17458
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctEmptyState, isStandalone: true, selector: "strct-empty-state", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-empty--sm": "size() === 'sm'", "attr.aria-busy": "variant() === 'loading' ? 'true' : null" }, classAttribute: "strct-empty" }, ngImport: i0, template: `
17335
17459
  <span class="strct-empty__icon strct-empty__icon--{{ toneClass() }}">
17336
- <strct-icon [name]="resolvedIcon()" [size]="26" [strokeWidth]="1.4" />
17460
+ @if (variant() === 'loading') {
17461
+ <strct-spinner [size]="size() === 'sm' ? 'sm' : 'md'" [label]="title()" />
17462
+ } @else {
17463
+ <strct-icon
17464
+ [name]="resolvedIcon()"
17465
+ [size]="size() === 'sm' ? 16 : 26"
17466
+ [strokeWidth]="1.4"
17467
+ />
17468
+ }
17337
17469
  </span>
17338
17470
  <h3 class="strct-empty__title">{{ title() }}</h3>
17339
17471
  @if (description()) {
17340
17472
  <p class="strct-empty__desc">{{ description() }}</p>
17341
17473
  }
17342
17474
  <div class="strct-empty__actions"><ng-content /></div>
17343
- `, isInline: true, styles: [".strct-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:40px 24px}.strct-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:14px;margin-bottom:2px}.strct-empty__icon--neutral{background:var(--bg-3);color:var(--t2)}.strct-empty__icon--warning{background:var(--warning-bg);color:var(--warning)}.strct-empty__icon--critical{background:var(--critical-bg);color:var(--critical)}.strct-empty__icon--accent{background:var(--acc-m);color:var(--acc)}.strct-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--t1)}.strct-empty__desc{margin:0;max-width:360px;font-size:13px;line-height:1.5;color:var(--t3)}.strct-empty__actions{display:flex;align-items:center;gap:8px;margin-top:6px}.strct-empty__actions:empty{display:none}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
17475
+ `, isInline: true, styles: [".strct-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:40px 24px}.strct-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:14px;margin-bottom:2px}.strct-empty__icon--neutral{background:var(--bg-3);color:var(--t2)}.strct-empty__icon--warning{background:var(--warning-bg);color:var(--warning)}.strct-empty__icon--critical{background:var(--critical-bg);color:var(--critical)}.strct-empty__icon--accent{background:var(--acc-m);color:var(--acc)}.strct-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--t1)}.strct-empty__desc{margin:0;max-width:360px;font-size:13px;line-height:1.5;color:var(--t3)}.strct-empty__actions{display:flex;align-items:center;gap:8px;margin-top:6px}.strct-empty__actions:empty{display:none}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
17344
17476
  }
17345
17477
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctEmptyState, decorators: [{
17346
17478
  type: Component,
17347
- args: [{ selector: 'strct-empty-state', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
17479
+ args: [{ selector: 'strct-empty-state', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctSpinner], template: `
17348
17480
  <span class="strct-empty__icon strct-empty__icon--{{ toneClass() }}">
17349
- <strct-icon [name]="resolvedIcon()" [size]="26" [strokeWidth]="1.4" />
17481
+ @if (variant() === 'loading') {
17482
+ <strct-spinner [size]="size() === 'sm' ? 'sm' : 'md'" [label]="title()" />
17483
+ } @else {
17484
+ <strct-icon
17485
+ [name]="resolvedIcon()"
17486
+ [size]="size() === 'sm' ? 16 : 26"
17487
+ [strokeWidth]="1.4"
17488
+ />
17489
+ }
17350
17490
  </span>
17351
17491
  <h3 class="strct-empty__title">{{ title() }}</h3>
17352
17492
  @if (description()) {
17353
17493
  <p class="strct-empty__desc">{{ description() }}</p>
17354
17494
  }
17355
17495
  <div class="strct-empty__actions"><ng-content /></div>
17356
- `, host: { class: 'strct-empty' }, styles: [".strct-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:40px 24px}.strct-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:14px;margin-bottom:2px}.strct-empty__icon--neutral{background:var(--bg-3);color:var(--t2)}.strct-empty__icon--warning{background:var(--warning-bg);color:var(--warning)}.strct-empty__icon--critical{background:var(--critical-bg);color:var(--critical)}.strct-empty__icon--accent{background:var(--acc-m);color:var(--acc)}.strct-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--t1)}.strct-empty__desc{margin:0;max-width:360px;font-size:13px;line-height:1.5;color:var(--t3)}.strct-empty__actions{display:flex;align-items:center;gap:8px;margin-top:6px}.strct-empty__actions:empty{display:none}\n"] }]
17357
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
17496
+ `, host: {
17497
+ class: 'strct-empty',
17498
+ '[class.strct-empty--sm]': "size() === 'sm'",
17499
+ '[attr.aria-busy]': "variant() === 'loading' ? 'true' : null",
17500
+ }, styles: [".strct-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:40px 24px}.strct-empty__icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:14px;margin-bottom:2px}.strct-empty__icon--neutral{background:var(--bg-3);color:var(--t2)}.strct-empty__icon--warning{background:var(--warning-bg);color:var(--warning)}.strct-empty__icon--critical{background:var(--critical-bg);color:var(--critical)}.strct-empty__icon--accent{background:var(--acc-m);color:var(--acc)}.strct-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--t1)}.strct-empty__desc{margin:0;max-width:360px;font-size:13px;line-height:1.5;color:var(--t3)}.strct-empty__actions{display:flex;align-items:center;gap:8px;margin-top:6px}.strct-empty__actions:empty{display:none}\n"] }]
17501
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
17358
17502
 
17359
17503
  /**
17360
17504
  * Unit formatting for infrastructure consoles — bytes, rates, durations and