@lifecorner/angular-ui-kit 3.20.0 → 3.21.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/fesm2022/lifecorner-angular-ui-kit-bar-chart.mjs +67 -8
- package/fesm2022/lifecorner-angular-ui-kit-bar-chart.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs +11 -11
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-diff-viewer.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-diff-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs +6 -6
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-markdown.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-markdown.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-status-dot.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-status-dot.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/theme-contrast.spec.ts +239 -0
- package/types/lifecorner-angular-ui-kit-bar-chart.d.ts +105 -10
|
@@ -60,7 +60,7 @@ var StatusDotComponent = class StatusDotComponent {
|
|
|
60
60
|
},
|
|
61
61
|
ngImport: i0,
|
|
62
62
|
template: "<span\n [class]=\"dotClasses()\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n></span>\n",
|
|
63
|
-
styles: ["@charset \"UTF-8\";lc-status-dot{display:inline-flex;align-items:center}.lc-status-dot{position:relative;display:inline-block;flex-shrink:0;border-radius:var(--border-radius-full, 9999px);background-color:currentColor}.lc-status-dot--sm{width:.375rem;height:.375rem}.lc-status-dot--md{width:.5rem;height:.5rem}.lc-status-dot--done{color:var(--color-success)}.lc-status-dot--run{color:var(--color-primary-500)}.lc-status-dot--wait{color:var(--color-warning)}.lc-status-dot--blocked{color:var(--color-error)}.lc-status-dot--open{color:var(--color-text-tertiary, var(--color-text-secondary))}.lc-status-dot--pulse:after{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;animation:lc-status-dot-pulse 1.6s ease-out infinite}@keyframes lc-status-dot-pulse{0%{transform:scale(1);opacity:.5}to{transform:scale(2.75);opacity:0}}@media(prefers-reduced-motion:reduce){.lc-status-dot--pulse:after{animation:none;display:none}}\n"],
|
|
63
|
+
styles: ["@charset \"UTF-8\";lc-status-dot{display:inline-flex;align-items:center}.lc-status-dot{position:relative;display:inline-block;flex-shrink:0;border-radius:var(--border-radius-full, 9999px);background-color:currentColor}.lc-status-dot--sm{width:.375rem;height:.375rem}.lc-status-dot--md{width:.5rem;height:.5rem}.lc-status-dot--done{color:var(--color-on-success-subtle)}.lc-status-dot--run{color:var(--color-primary-500)}.lc-status-dot--wait{color:var(--color-on-warning-subtle)}.lc-status-dot--blocked{color:var(--color-on-error-subtle)}.lc-status-dot--open{color:var(--color-text-tertiary, var(--color-text-secondary))}.lc-status-dot--pulse:after{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;animation:lc-status-dot-pulse 1.6s ease-out infinite}@keyframes lc-status-dot-pulse{0%{transform:scale(1);opacity:.5}to{transform:scale(2.75);opacity:0}}@media(prefers-reduced-motion:reduce){.lc-status-dot--pulse:after{animation:none;display:none}}\n"],
|
|
64
64
|
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
65
65
|
encapsulation: i0.ViewEncapsulation.None
|
|
66
66
|
});
|
|
@@ -79,7 +79,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
79
79
|
encapsulation: ViewEncapsulation.None,
|
|
80
80
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
81
81
|
template: "<span\n [class]=\"dotClasses()\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n></span>\n",
|
|
82
|
-
styles: ["@charset \"UTF-8\";lc-status-dot{display:inline-flex;align-items:center}.lc-status-dot{position:relative;display:inline-block;flex-shrink:0;border-radius:var(--border-radius-full, 9999px);background-color:currentColor}.lc-status-dot--sm{width:.375rem;height:.375rem}.lc-status-dot--md{width:.5rem;height:.5rem}.lc-status-dot--done{color:var(--color-success)}.lc-status-dot--run{color:var(--color-primary-500)}.lc-status-dot--wait{color:var(--color-warning)}.lc-status-dot--blocked{color:var(--color-error)}.lc-status-dot--open{color:var(--color-text-tertiary, var(--color-text-secondary))}.lc-status-dot--pulse:after{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;animation:lc-status-dot-pulse 1.6s ease-out infinite}@keyframes lc-status-dot-pulse{0%{transform:scale(1);opacity:.5}to{transform:scale(2.75);opacity:0}}@media(prefers-reduced-motion:reduce){.lc-status-dot--pulse:after{animation:none;display:none}}\n"]
|
|
82
|
+
styles: ["@charset \"UTF-8\";lc-status-dot{display:inline-flex;align-items:center}.lc-status-dot{position:relative;display:inline-block;flex-shrink:0;border-radius:var(--border-radius-full, 9999px);background-color:currentColor}.lc-status-dot--sm{width:.375rem;height:.375rem}.lc-status-dot--md{width:.5rem;height:.5rem}.lc-status-dot--done{color:var(--color-on-success-subtle)}.lc-status-dot--run{color:var(--color-primary-500)}.lc-status-dot--wait{color:var(--color-on-warning-subtle)}.lc-status-dot--blocked{color:var(--color-on-error-subtle)}.lc-status-dot--open{color:var(--color-text-tertiary, var(--color-text-secondary))}.lc-status-dot--pulse:after{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;animation:lc-status-dot-pulse 1.6s ease-out infinite}@keyframes lc-status-dot-pulse{0%{transform:scale(1);opacity:.5}to{transform:scale(2.75);opacity:0}}@media(prefers-reduced-motion:reduce){.lc-status-dot--pulse:after{animation:none;display:none}}\n"]
|
|
83
83
|
}]
|
|
84
84
|
}],
|
|
85
85
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-status-dot.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/status-dot/status-dot.component.ts","../../../../libs/angular-ui-kit/src/lib/status-dot/status-dot.component.html"],"sourcesContent":["import { Component, ChangeDetectionStrategy, ViewEncapsulation, input, computed } from '@angular/core';\n\nexport type StatusDotTone = 'done' | 'run' | 'wait' | 'blocked' | 'open';\nexport type StatusDotSize = 'sm' | 'md';\n\n/**\n * Status dot — the small traffic-light atom used in list rows, rails and\n * boards to signal an item's state at a glance.\n *\n * Features:\n * - Five semantic tones: done (success), run (brand teal), wait (warning),\n * blocked (error), open (neutral)\n * - Optional pulse animation for \"in progress\" states (static under\n * prefers-reduced-motion)\n * - Decorative by default (aria-hidden); pass `label` to expose the state\n * to assistive technology\n *\n * @example\n * ```html\n * <lc-status-dot tone=\"run\" [pulse]=\"true\" label=\"In Arbeit\" />\n * <lc-status-dot tone=\"blocked\" />\n * ```\n */\n@Component({\n selector: 'lc-status-dot',\n standalone: true,\n imports: [],\n templateUrl: './status-dot.component.html',\n styleUrl: './status-dot.component.scss',\n encapsulation: ViewEncapsulation.None, // Required for dynamic tone class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class StatusDotComponent {\n /** Semantic tone of the dot */\n readonly tone = input<StatusDotTone>('open');\n\n /** Size of the dot (sm = 6px for dense list rows, md = 8px) */\n readonly size = input<StatusDotSize>('md');\n\n /**\n * Pulse animation for \"in progress\" states. Renders static under\n * prefers-reduced-motion.\n * @default false\n */\n readonly pulse = input(false);\n\n /**\n * Accessible label for the state (e.g. \"In Arbeit\"). Without it the dot is\n * treated as decorative and hidden from assistive technology.\n */\n readonly label = input('');\n\n readonly dotClasses = computed(() => {\n const classes = ['lc-status-dot', `lc-status-dot--${this.tone()}`, `lc-status-dot--${this.size()}`];\n if (this.pulse()) {\n classes.push('lc-status-dot--pulse');\n }\n return classes.join(' ');\n });\n}\n","<span\n [class]=\"dotClasses()\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n></span>\n"],"mappings":";;AAgCA,IAAa,qBAAb,MAAa,mBAAkB;CAEpB,OAAO,MAAqB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAGnC,OAAO,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAOjC,QAAQ,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAMpB,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEjB,aAAa,eAAc;EAClC,MAAM,UAAU;GAAC;GAAiB,kBAAkB,KAAK,KAAI;GAAM,kBAAkB,KAAK,KAAI;EAAI;EAClG,IAAI,KAAK,MAAK,GACZ,QAAQ,KAAK,sBAAsB;EAErC,OAAO,QAAQ,KAAK,GAAG;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CA1BS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAkB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAlB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAkB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UChC/B;EAMA,QAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-status-dot.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/status-dot/status-dot.component.ts","../../../../libs/angular-ui-kit/src/lib/status-dot/status-dot.component.html"],"sourcesContent":["import { Component, ChangeDetectionStrategy, ViewEncapsulation, input, computed } from '@angular/core';\n\nexport type StatusDotTone = 'done' | 'run' | 'wait' | 'blocked' | 'open';\nexport type StatusDotSize = 'sm' | 'md';\n\n/**\n * Status dot — the small traffic-light atom used in list rows, rails and\n * boards to signal an item's state at a glance.\n *\n * Features:\n * - Five semantic tones: done (success), run (brand teal), wait (warning),\n * blocked (error), open (neutral)\n * - Optional pulse animation for \"in progress\" states (static under\n * prefers-reduced-motion)\n * - Decorative by default (aria-hidden); pass `label` to expose the state\n * to assistive technology\n *\n * @example\n * ```html\n * <lc-status-dot tone=\"run\" [pulse]=\"true\" label=\"In Arbeit\" />\n * <lc-status-dot tone=\"blocked\" />\n * ```\n */\n@Component({\n selector: 'lc-status-dot',\n standalone: true,\n imports: [],\n templateUrl: './status-dot.component.html',\n styleUrl: './status-dot.component.scss',\n encapsulation: ViewEncapsulation.None, // Required for dynamic tone class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class StatusDotComponent {\n /** Semantic tone of the dot */\n readonly tone = input<StatusDotTone>('open');\n\n /** Size of the dot (sm = 6px for dense list rows, md = 8px) */\n readonly size = input<StatusDotSize>('md');\n\n /**\n * Pulse animation for \"in progress\" states. Renders static under\n * prefers-reduced-motion.\n * @default false\n */\n readonly pulse = input(false);\n\n /**\n * Accessible label for the state (e.g. \"In Arbeit\"). Without it the dot is\n * treated as decorative and hidden from assistive technology.\n */\n readonly label = input('');\n\n readonly dotClasses = computed(() => {\n const classes = ['lc-status-dot', `lc-status-dot--${this.tone()}`, `lc-status-dot--${this.size()}`];\n if (this.pulse()) {\n classes.push('lc-status-dot--pulse');\n }\n return classes.join(' ');\n });\n}\n","<span\n [class]=\"dotClasses()\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n></span>\n"],"mappings":";;AAgCA,IAAa,qBAAb,MAAa,mBAAkB;CAEpB,OAAO,MAAqB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAGnC,OAAO,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAOjC,QAAQ,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAMpB,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEjB,aAAa,eAAc;EAClC,MAAM,UAAU;GAAC;GAAiB,kBAAkB,KAAK,KAAI;GAAM,kBAAkB,KAAK,KAAI;EAAI;EAClG,IAAI,KAAK,MAAK,GACZ,QAAQ,KAAK,sBAAsB;EAErC,OAAO,QAAQ,KAAK,GAAG;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CA1BS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAkB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAlB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAkB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UChC/B;EAMA,QAAA,CAAA,89BAAA;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AD0Ba,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAkB,YAAA,CAAA;EAT9B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAe,YACb;GAAI,SACP,CAAA;GAAE,eAGI,kBAAkB;GAAI,iBACpB,wBAAwB;GAAM,UAAA;GAAA,QAAA,CAAA,89BAAA;EAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -657,3 +657,242 @@ describe('Component pairings of 3.20 (request 027)', () => {
|
|
|
657
657
|
});
|
|
658
658
|
});
|
|
659
659
|
});
|
|
660
|
+
|
|
661
|
+
// Request 029 (3.21.1): the follow-up candidates of 027 design §5. Status
|
|
662
|
+
// colours used as text, icon, glyph, border or progress fill read the inks
|
|
663
|
+
// --color-on-<v>-subtle in both themes (WCAG 1.4.3 4.5:1 for text, 1.4.11 3:1
|
|
664
|
+
// for graphics). The shared fills, rails and line tints stay; the card and
|
|
665
|
+
// notification chips sit on --color-<v>-subtle (design 029 D-1).
|
|
666
|
+
describe('Component pairings of 3.21.1 (request 029)', () => {
|
|
667
|
+
const lib = (path: string) => resolve(__dirname, '../lib', path);
|
|
668
|
+
const sheets = {
|
|
669
|
+
nc: compile(lib('notification-center/notification-center.component.scss')).css,
|
|
670
|
+
card: compile(lib('card/card.component.scss')).css,
|
|
671
|
+
markdown: compile(lib('markdown/markdown.component.scss')).css,
|
|
672
|
+
dot: compile(lib('status-dot/status-dot.component.scss')).css,
|
|
673
|
+
pipeline: compile(lib('pipeline/pipeline.component.scss')).css,
|
|
674
|
+
upload: compile(lib('file-upload/file-upload.component.scss')).css,
|
|
675
|
+
rating: compile(lib('rating/rating.component.scss')).css,
|
|
676
|
+
log: compile(lib('log-viewer/log-viewer.component.scss')).css,
|
|
677
|
+
diff: compile(lib('diff-viewer/diff-viewer.component.scss')).css,
|
|
678
|
+
dep: compile(lib('dependency-viewer/dependency-viewer.component.scss')).css,
|
|
679
|
+
kanban: compile(lib('kanban-board/kanban-board.component.scss')).css,
|
|
680
|
+
progress: compile(lib('progress-bar/progress-bar.component.scss')).css,
|
|
681
|
+
};
|
|
682
|
+
type Sheet = keyof typeof sheets;
|
|
683
|
+
const rulesOf = (css: string) => [...css.matchAll(/([^{}]+)\{([^{}]*)\}/g)].map((m) => ({ selector: m[1].trim(), body: m[2] }));
|
|
684
|
+
const rule = (sheet: Sheet, selector: string) => {
|
|
685
|
+
const found = rulesOf(sheets[sheet]).filter((r) => r.selector === selector);
|
|
686
|
+
expect(found).toHaveLength(1);
|
|
687
|
+
return found[0].body;
|
|
688
|
+
};
|
|
689
|
+
/** The declarations of a rule body, property → value. */
|
|
690
|
+
const decls = (body: string): Record<string, string> =>
|
|
691
|
+
Object.fromEntries([...body.matchAll(/([\w-]+):\s*([^;]+);/g)].map((m) => [m[1], m[2].trim()]));
|
|
692
|
+
const ink = (v: string) => `var(--color-on-${v}-subtle)`;
|
|
693
|
+
const sub = (v: string) => `var(--color-${v}-subtle)`;
|
|
694
|
+
const fills = (sheet: Sheet, selector: string) => decls(rule(sheet, selector));
|
|
695
|
+
|
|
696
|
+
const swaps: [Sheet, string, Record<string, string>][] = [
|
|
697
|
+
...(['info', 'success', 'warning', 'error'] as const).map((v): [Sheet, string, Record<string, string>] => ['nc', `.lc-nc__item-icon--${v}`, { color: ink(v) }]),
|
|
698
|
+
['nc', '.lc-nc__item-priority--high', { background: sub('warning'), color: ink('warning') }],
|
|
699
|
+
['nc', '.lc-nc__item-priority--urgent', { background: sub('error'), color: ink('error') }],
|
|
700
|
+
...(['success', 'warning', 'error'] as const).map((v): [Sheet, string, Record<string, string>] => ['card', `.card__badge--${v}`, { 'background-color': sub(v), color: ink(v) }]),
|
|
701
|
+
['markdown', '.lc-markdown__mermaid-error', { color: ink('error') }],
|
|
702
|
+
['dot', '.lc-status-dot--done', { color: ink('success') }],
|
|
703
|
+
['dot', '.lc-status-dot--wait', { color: ink('warning') }],
|
|
704
|
+
['dot', '.lc-status-dot--blocked', { color: ink('error') }],
|
|
705
|
+
['pipeline', '.lc-pipeline__step--warning .lc-pipeline__node', { 'border-color': ink('warning'), color: ink('warning') }],
|
|
706
|
+
['pipeline', '.lc-pipeline__step--error .lc-pipeline__node', { 'border-color': ink('error'), color: ink('error') }],
|
|
707
|
+
['pipeline', '.lc-pipeline__step--complete .lc-pipeline__node', { 'background-color': 'var(--color-primary-500)', color: 'var(--color-surface)' }],
|
|
708
|
+
['upload', '.file-upload__file-remove:hover', { background: 'rgba(157, 14, 14, 0.18)', color: ink('error') }],
|
|
709
|
+
['rating', '.rating__icon--filled', { color: ink('warning') }],
|
|
710
|
+
['rating', '.rating__icon-fill', { color: ink('warning') }],
|
|
711
|
+
['log', '.lc-log-viewer__line--info .lc-log-viewer__level', { color: ink('info') }],
|
|
712
|
+
['log', '.lc-log-viewer__line--warn .lc-log-viewer__level', { color: ink('warning') }],
|
|
713
|
+
['log', '.lc-log-viewer__line--error .lc-log-viewer__level', { color: ink('error') }],
|
|
714
|
+
['log', '.lc-log-viewer__level-pill--error', { 'background-color': 'rgba(157, 14, 14, 0.18)', color: ink('error') }],
|
|
715
|
+
['log', '.lc-log-viewer__level-pill--warn', { 'background-color': 'rgba(225, 160, 64, 0.18)', color: ink('warning') }],
|
|
716
|
+
['log', '.lc-log-viewer__level-pill--active', { 'box-shadow': 'inset 0 0 0 1px currentColor' }],
|
|
717
|
+
['diff', '.lc-diff__stat--add', { color: ink('success') }],
|
|
718
|
+
['diff', '.lc-diff__stat--del', { color: ink('error') }],
|
|
719
|
+
['diff', '.lc-diff__line--added .lc-diff__prefix', { color: ink('success') }],
|
|
720
|
+
['diff', '.lc-diff__line--removed .lc-diff__prefix', { color: ink('error') }],
|
|
721
|
+
...(['success', 'warning', 'error'] as const).map((v): [Sheet, string, Record<string, string>] => ['dep', `.dep-viewer__detail-status--${v}`, { color: ink(v) }]),
|
|
722
|
+
['kanban', '.lc-kanban__column-limit--over', { color: ink('error') }],
|
|
723
|
+
...(['success', 'warning', 'error', 'info'] as const).flatMap((v): [Sheet, string, Record<string, string>][] => [
|
|
724
|
+
['progress', `.progress-bar--${v} .progress-bar__fill`, { 'background-color': ink(v) }],
|
|
725
|
+
['progress', `.progress-bar-circular--${v} .progress-bar-circular__fill`, { stroke: ink(v) }],
|
|
726
|
+
]),
|
|
727
|
+
];
|
|
728
|
+
|
|
729
|
+
it.each(swaps)('AC-1…10: %s %s reads the status ink (no raw colour)', (sheet, selector, expectedDecls) => {
|
|
730
|
+
const found = fills(sheet, selector);
|
|
731
|
+
for (const [property, value] of Object.entries(expectedDecls)) expect(found[property]).toBe(value);
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
it('AC-4: the notification type icons carry no hex fallback any more', () => {
|
|
735
|
+
expect(sheets.nc).not.toMatch(/#3b82f6|#22c55e|#f59e0b|#ef4444/i);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
it('D-2: the level pills stay at full opacity; the pressed pill gets an outline in forced colours', () => {
|
|
739
|
+
expect(fills('log', '.lc-log-viewer__level-pill').opacity).toBeUndefined();
|
|
740
|
+
expect(fills('log', '.lc-log-viewer__level-pill--active').opacity).toBeUndefined();
|
|
741
|
+
expect(sheets.log).toMatch(
|
|
742
|
+
/@media \(forced-colors: active\) \{\s*\.lc-log-viewer__level-pill--active:not\(:focus-visible\) \{\s*outline: 2px solid Highlight;\s*outline-offset: 1px;\s*\}/,
|
|
743
|
+
);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it('AC-10: the progress track is unchanged; primary and secondary stay raw', () => {
|
|
747
|
+
// The base rule (the forced-colours block repeats the selector with an outline).
|
|
748
|
+
expect(sheets.progress).toMatch(/\n\.progress-bar__track \{\s*flex: 1;\s*background-color: var\(--color-surface-hover\);/);
|
|
749
|
+
expect(fills('progress', '.progress-bar--primary .progress-bar__fill')['background-color']).toMatch(/^#[0-9a-f]{6}$/i);
|
|
750
|
+
expect(fills('progress', '.progress-bar--secondary .progress-bar__fill')['background-color']).toMatch(/^#[0-9a-f]{6}$/i);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it('AC-9: kanban priorities, dependency relations, arrows and node borders read the inks', () => {
|
|
754
|
+
const source = (path: string) => readFileSync(lib(path), 'utf8');
|
|
755
|
+
const kanban = source('kanban-board/kanban-board.component.ts');
|
|
756
|
+
const depTs = source('dependency-viewer/dependency-viewer.component.ts');
|
|
757
|
+
const depHtml = source('dependency-viewer/dependency-viewer.component.html');
|
|
758
|
+
for (const text of [kanban, depTs, depHtml]) {
|
|
759
|
+
expect(text).not.toMatch(/--color-(success|warning|error|info)-default/);
|
|
760
|
+
expect(text).not.toMatch(/#3b82f6/i);
|
|
761
|
+
}
|
|
762
|
+
const priorities: [string, string][] = [['critical', 'error'], ['high', 'warning'], ['medium', 'info'], ['low', 'success']];
|
|
763
|
+
for (const [priority, v] of priorities) {
|
|
764
|
+
expect(kanban).toContain(`case '${priority}': return '${ink(v)}';`);
|
|
765
|
+
}
|
|
766
|
+
const relations: [string, string][] = [['blocks', 'error'], ['references', 'info'], ['requires', 'warning'], ['implements', 'success']];
|
|
767
|
+
for (const [relation, v] of relations) {
|
|
768
|
+
expect(depTs).toMatch(new RegExp(`${relation}:\\s*\\{ color: '${ink(v).replace(/[()]/g, '\\$&')}'`));
|
|
769
|
+
expect(depHtml).toMatch(new RegExp(`<marker id="arrow-${relation}"[^>]*><path [^>]*fill="${ink(v).replace(/[()]/g, '\\$&')}"/>`));
|
|
770
|
+
}
|
|
771
|
+
for (const v of ['success', 'warning', 'error']) {
|
|
772
|
+
expect(depTs).toMatch(new RegExp(`${v}:\\s*\\{ bg: '[^']+', border: '${ink(v).replace(/[()]/g, '\\$&')}'`));
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Design 029 §5, per palette [light, dark]: the minimum over every listed
|
|
778
|
+
* element and its real backgrounds. Text 4.85 L (card success chip) and 4.60
|
|
779
|
+
* D (NC high on the panel top, card warning on surface-2); graphics 3.52 L
|
|
780
|
+
* (diff +, dependency success border) and 4.83 D (NC warning icon on an
|
|
781
|
+
* unread row). F-1: the NC high chip on an unread row in dark stays 3.67.
|
|
782
|
+
*/
|
|
783
|
+
const expected = { text: [4.85, 4.6], graphic: [3.52, 4.83], ncUnread: [5.52, 3.67], completeGlyph: [4.36, 9.12] };
|
|
784
|
+
const floor = (n: number) => Math.floor(n * 100) / 100;
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Design 029 §2/§5 (r1, review finding 1): the terminal is always dark, so
|
|
788
|
+
* its levels use its own palette in both themes. The nested block of 3.21.0
|
|
789
|
+
* compiled to `.lc-log-viewer__line--<lv> .lc-log-viewer--terminal
|
|
790
|
+
* .lc-log-viewer__level` (a line outside the terminal), never matched, and
|
|
791
|
+
* left the terminal levels on the theme's colours (light ink: warn 2.40).
|
|
792
|
+
*/
|
|
793
|
+
const terminalLevels: [string, string, number][] = [
|
|
794
|
+
['debug', '#9399b2', 5.81],
|
|
795
|
+
['info', '#89b4fa', 7.78],
|
|
796
|
+
['warn', '#f9e2af', 11.43],
|
|
797
|
+
['error', '#f38ba8', 6.19],
|
|
798
|
+
];
|
|
799
|
+
|
|
800
|
+
it('AC-9 (r1): the terminal levels read the terminal palette at (0,3,0); the dead selector shape is gone', () => {
|
|
801
|
+
for (const [lv, hexValue] of terminalLevels) {
|
|
802
|
+
// Three classes beat the log variant's `.lc-log-viewer__line--<lv> .lc-log-viewer__level` (0,2,0).
|
|
803
|
+
expect(fills('log', `.lc-log-viewer--terminal .lc-log-viewer__line--${lv} .lc-log-viewer__level`)).toEqual({ color: hexValue });
|
|
804
|
+
}
|
|
805
|
+
expect(sheets.log).not.toMatch(/\.lc-log-viewer__line--[\w-]+ \.lc-log-viewer--terminal/);
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it('AC-9 (r1): the terminal levels reach 4.5:1 on the terminal and its warn and error line tints, in both themes', () => {
|
|
809
|
+
const terminal = parse(fills('log', '.lc-log-viewer--terminal')['background-color']);
|
|
810
|
+
const lineTint = (lv: string) => over(parse(fills('log', `.lc-log-viewer--terminal .lc-log-viewer__line--${lv}`)['background-color']), terminal);
|
|
811
|
+
const bases: Record<string, Rgba> = { debug: terminal, info: terminal, warn: lineTint('warn'), error: lineTint('error') };
|
|
812
|
+
for (const [lv, hexValue, expectedRatio] of terminalLevels) {
|
|
813
|
+
const level = ratio(hexValue, bases[lv]);
|
|
814
|
+
expect(floor(level)).toBe(expectedRatio);
|
|
815
|
+
expect(level).toBeGreaterThanOrEqual(4.5);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
describe.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('%s palette', (_palette, tokens, i) => {
|
|
820
|
+
const c = (name: string) => color(tokens, name);
|
|
821
|
+
const S = c('--color-surface');
|
|
822
|
+
const S2 = c('--color-surface-2');
|
|
823
|
+
const BG = c('--color-background');
|
|
824
|
+
const LOW = c('--color-background-low');
|
|
825
|
+
const SUN = c('--color-surface-sunken');
|
|
826
|
+
const TILE = c('--color-muted-tile');
|
|
827
|
+
const hov = (base: Rgba) => over(c('--color-surface-hover'), base);
|
|
828
|
+
const sel = (base: Rgba) => over(c('--color-surface-selected'), base);
|
|
829
|
+
/** A token or literal from a rule body, composited over `base`. */
|
|
830
|
+
const layer = (value: string, base: Rgba) => {
|
|
831
|
+
const ref = value.match(/^var\((--[\w-]+)\)$/);
|
|
832
|
+
return over(ref ? c(ref[1]) : parse(value), base);
|
|
833
|
+
};
|
|
834
|
+
const inkOf = (v: string) => c(`--color-on-${v}-subtle`);
|
|
835
|
+
const lowest = (fg: Rgba, bases: Rgba[]) => Math.min(...bases.map((bg) => ratio(over(fg, bg), bg)));
|
|
836
|
+
|
|
837
|
+
const panel = [S2, S, hov(S)];
|
|
838
|
+
const unread = [sel(S2), sel(S)];
|
|
839
|
+
const chip = (sheet: Sheet, selector: string, v: string, bases: Rgba[]) => {
|
|
840
|
+
const d = fills(sheet, selector);
|
|
841
|
+
return lowest(inkOf(v), bases.map((b) => layer(d.background ?? d['background-color'], b)));
|
|
842
|
+
};
|
|
843
|
+
const tint = (sheet: Sheet, selector: string, property: string, base: Rgba) => layer(fills(sheet, selector)[property], base);
|
|
844
|
+
|
|
845
|
+
const text = () => [
|
|
846
|
+
chip('nc', '.lc-nc__item-priority--high', 'warning', panel),
|
|
847
|
+
chip('nc', '.lc-nc__item-priority--urgent', 'error', panel),
|
|
848
|
+
// A selected card's background is --color-surface-selected over the page.
|
|
849
|
+
...(['success', 'warning', 'error'] as const).map((v) => chip('card', `.card__badge--${v}`, v, [S, S2, hov(S), sel(BG), TILE])),
|
|
850
|
+
lowest(inkOf('error'), [BG, S, S2, LOW, SUN]),
|
|
851
|
+
lowest(inkOf('info'), [S, hov(S), tint('log', '.lc-log-viewer__line:hover', 'background-color', S)]),
|
|
852
|
+
lowest(inkOf('warning'), [tint('log', '.lc-log-viewer--log .lc-log-viewer__line--warn', 'background-color', S)]),
|
|
853
|
+
lowest(inkOf('error'), [tint('log', '.lc-log-viewer--log .lc-log-viewer__line--error', 'background-color', S)]),
|
|
854
|
+
lowest(inkOf('warning'), [tint('log', '.lc-log-viewer__level-pill--warn', 'background-color', S)]),
|
|
855
|
+
lowest(inkOf('error'), [tint('log', '.lc-log-viewer__level-pill--error', 'background-color', S)]),
|
|
856
|
+
lowest(inkOf('success'), [S2]),
|
|
857
|
+
lowest(inkOf('error'), [S2]),
|
|
858
|
+
...['success', 'warning', 'error', 'info'].map((v) => lowest(inkOf(v), [S, S2])),
|
|
859
|
+
lowest(inkOf('error'), [layer('var(--color-error-50)', S), layer('var(--color-error-50)', BG)]),
|
|
860
|
+
];
|
|
861
|
+
|
|
862
|
+
const graphic = () => [
|
|
863
|
+
...['success', 'warning', 'error', 'info'].map((v) => lowest(inkOf(v), [...panel, ...unread])),
|
|
864
|
+
...['success', 'warning', 'error'].map((v) => lowest(inkOf(v), [S, BG, S2])),
|
|
865
|
+
lowest(inkOf('error'), [tint('upload', '.file-upload__file-remove:hover', 'background', S2)]),
|
|
866
|
+
...['success', 'error'].map((v) => lowest(inkOf(v), [layer(`var(--color-${v}-50)`, S), layer(`var(--color-${v}-50)`, BG)])),
|
|
867
|
+
...['success', 'warning', 'error'].map((v) => lowest(inkOf(v), [layer(`var(--color-${v}-50)`, S), S])),
|
|
868
|
+
...['success', 'warning', 'error', 'info'].map((v) => lowest(inkOf(v), [S])),
|
|
869
|
+
...['success', 'warning', 'error', 'info'].map((v) => lowest(inkOf(v), [hov(S), hov(BG), hov(S2)])),
|
|
870
|
+
];
|
|
871
|
+
|
|
872
|
+
it('AC-1/2/3/9: every listed status text reaches 4.5:1 on its real backgrounds', () => {
|
|
873
|
+
const min = Math.min(...text());
|
|
874
|
+
expect(floor(min)).toBe(expected.text[i]);
|
|
875
|
+
expect(min).toBeGreaterThanOrEqual(4.5);
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
it('AC-4…10: every listed status icon, glyph, border and progress fill reaches 3:1', () => {
|
|
879
|
+
const min = Math.min(...graphic());
|
|
880
|
+
expect(floor(min)).toBe(expected.graphic[i]);
|
|
881
|
+
expect(min).toBeGreaterThanOrEqual(3);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it('D-4: the pipeline complete check reaches 3:1 on its node fill', () => {
|
|
885
|
+
const glyph = ratio(c('--color-surface'), c('--color-primary-500'));
|
|
886
|
+
expect(floor(glyph)).toBe(expected.completeGlyph[i]);
|
|
887
|
+
expect(glyph).toBeGreaterThanOrEqual(3);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
it('F-1 (known): the NC priority chips on an unread row', () => {
|
|
891
|
+
const min = Math.min(
|
|
892
|
+
chip('nc', '.lc-nc__item-priority--high', 'warning', unread),
|
|
893
|
+
chip('nc', '.lc-nc__item-priority--urgent', 'error', unread),
|
|
894
|
+
);
|
|
895
|
+
expect(floor(min)).toBe(expected.ncUnread[i]);
|
|
896
|
+
});
|
|
897
|
+
});
|
|
898
|
+
});
|
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
import { ChartValueFormatter } from "@lifecorner/angular-ui-kit/internal/chart";
|
|
2
1
|
import * as i0 from "@angular/core";
|
|
3
2
|
export interface BarChartItem {
|
|
4
3
|
/** Bar value. Negative values draw downward (left) from the zero baseline. */
|
|
5
4
|
value: number;
|
|
6
5
|
label?: string;
|
|
7
6
|
color?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The text shown as this bar's value and read in the generated aria label,
|
|
9
|
+
* instead of `formatValue(value, item)`, for example "313.000,00 · 54,8 %".
|
|
10
|
+
* The kit shows it as given and never formats or computes it. An empty
|
|
11
|
+
* string shows no value for this bar.
|
|
12
|
+
*/
|
|
13
|
+
valueText?: string;
|
|
8
14
|
}
|
|
9
15
|
export type BarChartOrientation = 'vertical' | 'horizontal';
|
|
16
|
+
/**
|
|
17
|
+
* How the category labels are set: `'axis'` (one line of SVG text on the
|
|
18
|
+
* category axis) or `'wrap'` (HTML text that wraps and follows the text size).
|
|
19
|
+
*/
|
|
20
|
+
export type BarChartLabelLayout = 'axis' | 'wrap';
|
|
21
|
+
/**
|
|
22
|
+
* Signature of `lc-bar-chart`'s `formatValue`. A bar's value label passes the
|
|
23
|
+
* bar's item; an axis tick passes the tick only (`item` is `undefined`).
|
|
24
|
+
* One-argument formatters keep working.
|
|
25
|
+
*/
|
|
26
|
+
export type BarChartValueFormatter = (value: number, item?: BarChartItem) => string;
|
|
10
27
|
export declare class BarChartComponent {
|
|
11
28
|
private readonly _el;
|
|
12
29
|
private readonly _destroyRef;
|
|
@@ -20,28 +37,71 @@ export declare class BarChartComponent {
|
|
|
20
37
|
* `width` is the viewBox width until the container has been measured and,
|
|
21
38
|
* when set, the host's `max-width`, so the chart never grows past it. Leave
|
|
22
39
|
* unset for a fully fluid chart.
|
|
40
|
+
* @default undefined
|
|
23
41
|
*/
|
|
24
42
|
width: import("@angular/core").InputSignal<number | undefined>;
|
|
25
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Chart height in pixels. A horizontal `'wrap'` chart takes the height of
|
|
45
|
+
* its rows; a vertical `'wrap'` chart adds its label row below this height.
|
|
46
|
+
* @default 200
|
|
47
|
+
*/
|
|
26
48
|
height: import("@angular/core").InputSignal<number>;
|
|
27
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Bar orientation.
|
|
51
|
+
* @default 'vertical'
|
|
52
|
+
*/
|
|
28
53
|
orientation: import("@angular/core").InputSignal<BarChartOrientation>;
|
|
29
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Show value labels on bars. In horizontal `'wrap'` rows the value sits at
|
|
56
|
+
* the end of the label line.
|
|
57
|
+
* @default true
|
|
58
|
+
*/
|
|
30
59
|
showValues: import("@angular/core").InputSignal<boolean>;
|
|
31
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Show axis labels.
|
|
62
|
+
* @default true
|
|
63
|
+
*/
|
|
32
64
|
showLabels: import("@angular/core").InputSignal<boolean>;
|
|
33
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* How the category labels are set. `'axis'`: one line of SVG text on the
|
|
67
|
+
* category axis, in a fixed 40 px band left of a horizontal bar or centred
|
|
68
|
+
* under a vertical column. Long labels can run out of the chart. `'wrap'`:
|
|
69
|
+
* HTML text that wraps to the room it needs and follows the text size. A
|
|
70
|
+
* horizontal chart becomes a list of rows: the label and the value on one
|
|
71
|
+
* line (the value moves under the label when both don't fit), and below
|
|
72
|
+
* them the bar across the full width. The longest bar fills the width, and
|
|
73
|
+
* `height`, `barGap` and `showGrid` don't apply. A vertical chart keeps its
|
|
74
|
+
* plot and wraps each label within its column, under the chart.
|
|
75
|
+
* @default 'axis'
|
|
76
|
+
*/
|
|
77
|
+
labelLayout: import("@angular/core").InputSignal<BarChartLabelLayout>;
|
|
78
|
+
/**
|
|
79
|
+
* Show grid lines. Not used by horizontal `'wrap'` rows.
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
34
82
|
showGrid: import("@angular/core").InputSignal<boolean>;
|
|
35
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Gap between bars as ratio (0-1). Not used by horizontal `'wrap'` rows.
|
|
85
|
+
* @default 0.3
|
|
86
|
+
*/
|
|
36
87
|
barGap: import("@angular/core").InputSignal<number>;
|
|
37
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Use a single color for all bars.
|
|
90
|
+
* @default ''
|
|
91
|
+
*/
|
|
38
92
|
color: import("@angular/core").InputSignal<string>;
|
|
39
|
-
/**
|
|
40
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Formats the value labels and the axis ticks. For a bar it gets the bar's
|
|
95
|
+
* item as the second argument; for an axis tick it gets the tick only
|
|
96
|
+
* (`item` is `undefined`). An item's `valueText` takes precedence.
|
|
97
|
+
* @default float-safe `String(value)`
|
|
98
|
+
*/
|
|
99
|
+
formatValue: import("@angular/core").InputSignal<BarChartValueFormatter>;
|
|
41
100
|
/**
|
|
42
101
|
* Accessible name of the chart. Defaults to a generated summary that lists
|
|
43
102
|
* every bar's label and value, so assistive technology hears the data and
|
|
44
103
|
* not just "Bar chart".
|
|
104
|
+
* @default ''
|
|
45
105
|
*/
|
|
46
106
|
ariaLabel: import("@angular/core").InputSignal<string>;
|
|
47
107
|
private readonly PADDING_LEFT;
|
|
@@ -51,7 +111,19 @@ export declare class BarChartComponent {
|
|
|
51
111
|
protected readonly effectiveWidth: import("@angular/core").Signal<number>;
|
|
52
112
|
protected readonly viewBox: import("@angular/core").Signal<string>;
|
|
53
113
|
protected readonly isVertical: import("@angular/core").Signal<boolean>;
|
|
114
|
+
/** Horizontal `'wrap'`: HTML rows instead of the SVG plot. */
|
|
115
|
+
protected readonly wrapRows: import("@angular/core").Signal<boolean>;
|
|
116
|
+
/** Vertical `'wrap'`: the SVG plot, with the category labels as an HTML row under it. */
|
|
117
|
+
protected readonly wrapColumns: import("@angular/core").Signal<boolean>;
|
|
118
|
+
/**
|
|
119
|
+
* Room under the plot. `'axis'` keeps 30 for the SVG labels; vertical
|
|
120
|
+
* `'wrap'` labels sit under the SVG, so only 2 are left, or 18 when a
|
|
121
|
+
* negative bar's value label hangs below it.
|
|
122
|
+
*/
|
|
123
|
+
private readonly paddingBottom;
|
|
54
124
|
private readonly plot;
|
|
125
|
+
/** A bar's text: `valueText`, else `formatValue(value, item)`. */
|
|
126
|
+
private textOf;
|
|
55
127
|
/**
|
|
56
128
|
* One scale for grid *and* bars: bounds are nice multiples of the tick step,
|
|
57
129
|
* always include zero, and extend below zero when the data does — so the top
|
|
@@ -95,6 +167,24 @@ export declare class BarChartComponent {
|
|
|
95
167
|
}>;
|
|
96
168
|
/** Bottom edge of the plot — where horizontal-orientation tick labels sit. */
|
|
97
169
|
protected readonly plotBottom: import("@angular/core").Signal<number>;
|
|
170
|
+
/**
|
|
171
|
+
* Bounds of the horizontal `'wrap'` rows: zero is always inside, and the
|
|
172
|
+
* longest bar fills the track.
|
|
173
|
+
*/
|
|
174
|
+
private readonly rowBounds;
|
|
175
|
+
/**
|
|
176
|
+
* Horizontal `'wrap'` rows. Bar `x` and `width` are percentages of the
|
|
177
|
+
* track, so the server HTML is final before the container is measured.
|
|
178
|
+
*/
|
|
179
|
+
protected readonly rows: import("@angular/core").Signal<{
|
|
180
|
+
label: string;
|
|
181
|
+
valueText: string;
|
|
182
|
+
color: string;
|
|
183
|
+
x: string;
|
|
184
|
+
width: string;
|
|
185
|
+
}[]>;
|
|
186
|
+
/** Position of the zero line in the `'wrap'` rows; `null` without negative values. */
|
|
187
|
+
protected readonly rowZero: import("@angular/core").Signal<string | null>;
|
|
98
188
|
protected readonly effectiveAriaLabel: import("@angular/core").Signal<string>;
|
|
99
189
|
static ɵfac: i0.ɵɵFactoryDeclaration<BarChartComponent, never>;
|
|
100
190
|
static ɵcmp: i0.ɵɵComponentDeclaration<BarChartComponent, "lc-bar-chart", never, {
|
|
@@ -128,6 +218,11 @@ export declare class BarChartComponent {
|
|
|
128
218
|
"required": false;
|
|
129
219
|
"isSignal": true;
|
|
130
220
|
};
|
|
221
|
+
"labelLayout": {
|
|
222
|
+
"alias": "labelLayout";
|
|
223
|
+
"required": false;
|
|
224
|
+
"isSignal": true;
|
|
225
|
+
};
|
|
131
226
|
"showGrid": {
|
|
132
227
|
"alias": "showGrid";
|
|
133
228
|
"required": false;
|