@dataengineeringformachinelearning/viking-ui 4.0.3 → 4.0.5

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.
Files changed (246) hide show
  1. package/README.md +35 -11
  2. package/dist/README.md +35 -11
  3. package/dist/design-tokens.css +300 -85
  4. package/dist/fesm2022/dataengineeringformachinelearning-viking-ui.mjs +135 -70
  5. package/dist/fesm2022/dataengineeringformachinelearning-viking-ui.mjs.map +1 -1
  6. package/dist/icons.js +306 -0
  7. package/dist/package.json +24 -5
  8. package/{src/lib/site-drakkar/site-drakkar.config.ts → dist/site-drakkar.js} +64 -130
  9. package/dist/src/tokens/viking-tokens.json +9 -7
  10. package/dist/types/dataengineeringformachinelearning-viking-ui.d.ts +98 -4
  11. package/dist/viking-components.css +161 -70
  12. package/dist/viking-tokens.json +9 -7
  13. package/dist/viking-ui-elements.js +45 -33
  14. package/dist/viking-ui.css +1 -1
  15. package/dist/web-components.js +46 -36
  16. package/package.json +30 -8
  17. package/dist/scripts/build-web-components.mjs +0 -37
  18. package/dist/src/web/badge/viking-badge-wc.ts +0 -116
  19. package/dist/src/web/button/viking-button-wc.ts +0 -165
  20. package/dist/src/web/callout/viking-callout-wc.ts +0 -105
  21. package/dist/src/web/card/viking-card-wc.ts +0 -70
  22. package/dist/src/web/core/base.ts +0 -56
  23. package/dist/src/web/core/dom.ts +0 -53
  24. package/dist/src/web/core/icons-inline.ts +0 -44
  25. package/dist/src/web/core/styles.ts +0 -1261
  26. package/dist/src/web/core/types.ts +0 -19
  27. package/dist/src/web/field/viking-field-wc.ts +0 -154
  28. package/dist/src/web/index.ts +0 -73
  29. package/dist/src/web/input/viking-input-wc.ts +0 -211
  30. package/dist/src/web/modal/viking-modal-wc.ts +0 -187
  31. package/dist/src/web/search-palette/viking-search-palette-wc.ts +0 -494
  32. package/dist/src/web/select/viking-select-wc.ts +0 -218
  33. package/dist/src/web/suite-header/viking-suite-header-wc.ts +0 -729
  34. package/dist/src/web/suite-search-palette/viking-suite-search-palette-wc.ts +0 -234
  35. package/dist/src/web/theme-toggle/viking-theme-toggle-wc.ts +0 -139
  36. package/dist/src/web/types.ts +0 -37
  37. package/dist/src/web/web-components.spec.ts +0 -297
  38. package/src/assets/drakkar-favicon.svg +0 -17
  39. package/src/assets/fonts/inter/InterVariable-Italic.woff2 +0 -0
  40. package/src/assets/fonts/inter/InterVariable.woff2 +0 -0
  41. package/src/core/brand/deml-lockup.svg +0 -5
  42. package/src/core/brand/deml-mark-compact.svg +0 -4
  43. package/src/core/brand/deml-mark-filled.svg +0 -3
  44. package/src/core/brand/deml-mark-outline.svg +0 -4
  45. package/src/core/brand-icons.ts +0 -62
  46. package/src/core/icons.spec.ts +0 -52
  47. package/src/core/icons.ts +0 -206
  48. package/src/core/integration-brand-icons.ts +0 -77
  49. package/src/core/lucide-paths.generated.ts +0 -130
  50. package/src/core/types.ts +0 -85
  51. package/src/core/uid.ts +0 -7
  52. package/src/elements/button/viking-button.ts +0 -201
  53. package/src/elements/card/viking-card.ts +0 -60
  54. package/src/elements/core/dom.ts +0 -33
  55. package/src/elements/core/styles.ts +0 -28
  56. package/src/elements/modal/viking-modal.ts +0 -154
  57. package/src/index.ts +0 -1
  58. package/src/lib/accordion/accordion.ts +0 -126
  59. package/src/lib/app-header/app-header.scss +0 -274
  60. package/src/lib/app-header/app-header.ts +0 -43
  61. package/src/lib/app-sidebar/app-sidebar.scss +0 -415
  62. package/src/lib/app-sidebar/app-sidebar.ts +0 -29
  63. package/src/lib/auth-panel/auth-panel.spec.ts +0 -132
  64. package/src/lib/auth-panel/auth-panel.ts +0 -228
  65. package/src/lib/autocomplete/autocomplete.ts +0 -223
  66. package/src/lib/avatar/avatar.ts +0 -126
  67. package/src/lib/badge/badge.ts +0 -182
  68. package/src/lib/bar/bar.ts +0 -31
  69. package/src/lib/brand/brand.ts +0 -60
  70. package/src/lib/breadcrumbs/breadcrumbs.ts +0 -81
  71. package/src/lib/button/button-group.ts +0 -40
  72. package/src/lib/button/button.scss +0 -119
  73. package/src/lib/button/button.ts +0 -98
  74. package/src/lib/calendar/calendar.ts +0 -253
  75. package/src/lib/callout/callout.ts +0 -211
  76. package/src/lib/card/card-title.spec.ts +0 -27
  77. package/src/lib/card/card-title.ts +0 -50
  78. package/src/lib/card/card.ts +0 -198
  79. package/src/lib/carousel/carousel.ts +0 -206
  80. package/src/lib/chart/chart-zoom.spec.ts +0 -65
  81. package/src/lib/chart/chart-zoom.ts +0 -71
  82. package/src/lib/chart/chart.ts +0 -1257
  83. package/src/lib/chart-card-header/chart-card-header.ts +0 -80
  84. package/src/lib/chart-empty-state/chart-empty-state.ts +0 -146
  85. package/src/lib/chart-panel/chart-panel.ts +0 -133
  86. package/src/lib/checkbox/checkbox.ts +0 -139
  87. package/src/lib/color-picker/color-picker.ts +0 -148
  88. package/src/lib/command/command.ts +0 -260
  89. package/src/lib/composer/composer.ts +0 -180
  90. package/src/lib/confirm-dialog/confirm-dialog.ts +0 -163
  91. package/src/lib/confirm-dialog/dialog.service.ts +0 -79
  92. package/src/lib/context/context.ts +0 -75
  93. package/src/lib/core/brand-icons.ts +0 -62
  94. package/src/lib/core/cva.ts +0 -33
  95. package/src/lib/core/icons.ts +0 -206
  96. package/src/lib/core/integration-brand-icons.ts +0 -77
  97. package/src/lib/core/lucide-paths.generated.ts +0 -130
  98. package/src/lib/date-picker/date-picker.ts +0 -139
  99. package/src/lib/dropdown/dropdown.ts +0 -188
  100. package/src/lib/editor/editor.ts +0 -170
  101. package/src/lib/empty-state/empty-state.ts +0 -100
  102. package/src/lib/fab/fab.ts +0 -76
  103. package/src/lib/field/field.ts +0 -111
  104. package/src/lib/file-upload/file-upload.ts +0 -208
  105. package/src/lib/footer/footer.scss +0 -155
  106. package/src/lib/footer/footer.ts +0 -28
  107. package/src/lib/form-section/form-section.ts +0 -200
  108. package/src/lib/forms.spec.ts +0 -92
  109. package/src/lib/gauge-arc/gauge-arc.ts +0 -85
  110. package/src/lib/hud-panel/hud-panel.ts +0 -27
  111. package/src/lib/icon/icon.ts +0 -284
  112. package/src/lib/icon-badge/icon-badge.ts +0 -87
  113. package/src/lib/icon-heading/icon-heading.spec.ts +0 -32
  114. package/src/lib/icon-heading/icon-heading.ts +0 -38
  115. package/src/lib/icon-text/icon-text.ts +0 -120
  116. package/src/lib/input/input.ts +0 -119
  117. package/src/lib/kanban/kanban.ts +0 -211
  118. package/src/lib/kbd/kbd.ts +0 -32
  119. package/src/lib/label/label.ts +0 -39
  120. package/src/lib/loading-overlay/loading-overlay.ts +0 -80
  121. package/src/lib/menubar/menubar.ts +0 -77
  122. package/src/lib/metric-card/metric-card.ts +0 -33
  123. package/src/lib/modal/modal.ts +0 -207
  124. package/src/lib/native-select/native-select.ts +0 -124
  125. package/src/lib/navbar/navbar.ts +0 -124
  126. package/src/lib/navigation-menu/navigation-menu.ts +0 -116
  127. package/src/lib/otp-input/otp-input.ts +0 -164
  128. package/src/lib/page-back-link/page-back-link.ts +0 -74
  129. package/src/lib/page-header/page-header.ts +0 -70
  130. package/src/lib/pagination/pagination.ts +0 -157
  131. package/src/lib/pillbox/pillbox.ts +0 -157
  132. package/src/lib/popover/popover.ts +0 -92
  133. package/src/lib/profile/profile.ts +0 -73
  134. package/src/lib/progress/progress.ts +0 -123
  135. package/src/lib/radio/radio.ts +0 -132
  136. package/src/lib/ring-gauge/ring-gauge.ts +0 -75
  137. package/src/lib/scroll-area/scroll-area.ts +0 -57
  138. package/src/lib/search-palette/search-palette.scss +0 -288
  139. package/src/lib/search-palette/search-palette.ts +0 -114
  140. package/src/lib/select/select.ts +0 -292
  141. package/src/lib/separator/separator.ts +0 -59
  142. package/src/lib/sheet/sheet.ts +0 -192
  143. package/src/lib/sidebar-nav/sidebar-nav.scss +0 -218
  144. package/src/lib/sidebar-nav/sidebar-nav.ts +0 -158
  145. package/src/lib/site-drakkar/site-footer.ts +0 -129
  146. package/src/lib/site-drakkar/site-navbar.scss +0 -2
  147. package/src/lib/site-drakkar/site-navbar.ts +0 -277
  148. package/src/lib/site-drakkar/suite-search-items.spec.ts +0 -61
  149. package/src/lib/site-drakkar/suite-search-items.ts +0 -246
  150. package/src/lib/skeleton/skeleton.ts +0 -51
  151. package/src/lib/slider/slider.ts +0 -133
  152. package/src/lib/spinner/spinner.ts +0 -75
  153. package/src/lib/status-metric-row/status-metric-row.ts +0 -74
  154. package/src/lib/suite-search-palette/suite-search-palette.ts +0 -95
  155. package/src/lib/switch/switch.ts +0 -131
  156. package/src/lib/table/table.ts +0 -137
  157. package/src/lib/tabs/tab-panel.ts +0 -61
  158. package/src/lib/tabs/tab.ts +0 -107
  159. package/src/lib/tabs/tabs.ts +0 -109
  160. package/src/lib/textarea/textarea.ts +0 -103
  161. package/src/lib/theme-toggle/theme-toggle.spec.ts +0 -40
  162. package/src/lib/theme-toggle/theme-toggle.ts +0 -39
  163. package/src/lib/time-picker/time-picker.ts +0 -197
  164. package/src/lib/timeline/timeline.ts +0 -152
  165. package/src/lib/toast/toast.ts +0 -196
  166. package/src/lib/toggle/toggle-group.ts +0 -60
  167. package/src/lib/toggle/toggle.ts +0 -101
  168. package/src/lib/tooltip/tooltip.ts +0 -119
  169. package/src/lib/typography/heading.ts +0 -52
  170. package/src/lib/typography/text.ts +0 -51
  171. package/src/lib/uptime-bar/uptime-bar.ts +0 -55
  172. package/src/lib/verification-code-field/verification-code-field.ts +0 -149
  173. package/src/lib/whitepaper-cta/whitepaper-cta.scss +0 -130
  174. package/src/lib/whitepaper-cta/whitepaper-cta.ts +0 -78
  175. package/src/lib/wizard/wizard.ts +0 -80
  176. package/src/public-api.ts +0 -172
  177. package/src/styles/_buttons.scss +0 -386
  178. package/src/styles/_component-primitives.scss +0 -183
  179. package/src/styles/_drakkar-buttons.scss +0 -85
  180. package/src/styles/_fonts.scss +0 -22
  181. package/src/styles/_forms.scss +0 -66
  182. package/src/styles/_input.scss +0 -106
  183. package/src/styles/_layout-enforcement.scss +0 -229
  184. package/src/styles/_layout-rhythm.scss +0 -158
  185. package/src/styles/_legacy-aliases.scss +0 -212
  186. package/src/styles/_series-colors.scss +0 -24
  187. package/src/styles/_static-primitives.scss +0 -857
  188. package/src/styles/_typography.scss +0 -87
  189. package/src/styles/_variables.scss +0 -527
  190. package/src/styles/components/a11y.scss +0 -90
  191. package/src/styles/components/badges.scss +0 -102
  192. package/src/styles/components/extracted-utilities.scss +0 -459
  193. package/src/styles/components/footer.scss +0 -155
  194. package/src/styles/components/icon-heading.scss +0 -47
  195. package/src/styles/components/icon-inline.scss +0 -101
  196. package/src/styles/components/layout.scss +0 -59
  197. package/src/styles/components/utilities.scss +0 -131
  198. package/src/styles/components/viking-inspired.scss +0 -204
  199. package/src/styles/components/whitepaper-cta.scss +0 -130
  200. package/src/styles/components-bundle.scss +0 -9
  201. package/src/styles/components.scss +0 -442
  202. package/src/styles/deml-components.scss +0 -10
  203. package/src/styles/index.scss +0 -8
  204. package/src/styles/layout-shell.scss +0 -111
  205. package/src/styles/page-shell.scss +0 -859
  206. package/src/styles/static-navbar.scss +0 -1215
  207. package/src/styles/surfaces/backend.scss +0 -154
  208. package/src/styles/surfaces/docs-global.scss +0 -73
  209. package/src/styles/surfaces/docs-shell.scss +0 -437
  210. package/src/styles/surfaces/docs-showcase.scss +0 -1153
  211. package/src/styles/surfaces/marketing-cta.scss +0 -62
  212. package/src/styles/surfaces/marketing-docs-bento.scss +0 -67
  213. package/src/styles/surfaces/marketing-global.scss +0 -748
  214. package/src/styles/surfaces/marketing-landing.scss +0 -1526
  215. package/src/styles/surfaces/marketing-publication.scss +0 -535
  216. package/src/styles/surfaces/marketing-theme.scss +0 -14
  217. package/src/styles/surfaces/swagger-ui.scss +0 -922
  218. package/src/styles/tokens-export.scss +0 -18
  219. package/src/styles/tokens.scss +0 -5
  220. package/src/styles/viking-ui-bundle.scss +0 -23
  221. package/src/styles/viking-ui.scss +0 -270
  222. package/src/tokens/series-presets.ts +0 -15
  223. package/src/tokens/tailwind.preset.js +0 -209
  224. package/src/tokens/viking-tokens.json +0 -318
  225. package/src/viking-ui.spec.ts +0 -416
  226. package/src/web/badge/viking-badge-wc.ts +0 -116
  227. package/src/web/button/viking-button-wc.ts +0 -165
  228. package/src/web/callout/viking-callout-wc.ts +0 -105
  229. package/src/web/card/viking-card-wc.ts +0 -70
  230. package/src/web/core/base.ts +0 -56
  231. package/src/web/core/dom.ts +0 -53
  232. package/src/web/core/icons-inline.ts +0 -44
  233. package/src/web/core/styles.ts +0 -1261
  234. package/src/web/core/types.ts +0 -19
  235. package/src/web/field/viking-field-wc.ts +0 -154
  236. package/src/web/index.ts +0 -73
  237. package/src/web/input/viking-input-wc.ts +0 -211
  238. package/src/web/modal/viking-modal-wc.ts +0 -187
  239. package/src/web/search-palette/viking-search-palette-wc.ts +0 -494
  240. package/src/web/select/viking-select-wc.ts +0 -218
  241. package/src/web/suite-header/viking-suite-header-wc.ts +0 -729
  242. package/src/web/suite-search-palette/viking-suite-search-palette-wc.ts +0 -234
  243. package/src/web/theme-toggle/viking-theme-toggle-wc.ts +0 -139
  244. package/src/web/types.ts +0 -37
  245. package/src/web/web-components.spec.ts +0 -297
  246. package/src/web-components/index.ts +0 -1
@@ -1,92 +0,0 @@
1
- import { Component } from "@angular/core";
2
- import { TestBed, ComponentFixture } from "@angular/core/testing";
3
- import { FormsModule } from "@angular/forms";
4
- import { describe, it, expect } from "vitest";
5
- import { VikingField } from "./field/field";
6
- import { VikingInput } from "./input/input";
7
- import { VikingFormSection } from "./form-section/form-section";
8
-
9
- @Component({
10
- imports: [VikingField, VikingInput, FormsModule],
11
- template: `
12
- <viking-field label="Email" [required]="true" [error]="error">
13
- <viking-input [(ngModel)]="email" placeholder="you@example.com" />
14
- </viking-field>
15
- `,
16
- })
17
- class FieldInputHost {
18
- email = "";
19
- error = "";
20
- }
21
-
22
- @Component({
23
- imports: [VikingFormSection, VikingField, VikingInput, FormsModule],
24
- template: `
25
- <viking-form-section heading="Profile" icon="user" layout="stack">
26
- <viking-field label="Display name">
27
- <viking-input [(ngModel)]="name" />
28
- </viking-field>
29
- </viking-form-section>
30
- `,
31
- })
32
- class FormStackHost {
33
- name = "";
34
- }
35
-
36
- describe("viking forms", () => {
37
- const render = async <T>(
38
- component: new () => T,
39
- ): Promise<ComponentFixture<T>> => {
40
- const fixture = TestBed.createComponent(component);
41
- fixture.detectChanges();
42
- await fixture.whenStable();
43
- return fixture;
44
- };
45
-
46
- it("renders required marker and associates label with input", async () => {
47
- const fixture = await render(FieldInputHost);
48
- const label = fixture.nativeElement.querySelector(".viking-field-label");
49
- expect(label?.textContent).toContain("Email");
50
- expect(label?.querySelector(".viking-field-required")).toBeTruthy();
51
- expect(fixture.nativeElement.querySelector("viking-input-wc")).toBeTruthy();
52
- });
53
-
54
- it("shows error alert and invalid host class", async () => {
55
- const fixture = await render(FieldInputHost);
56
- fixture.componentInstance.error = "Invalid email address";
57
- fixture.detectChanges();
58
- const field = fixture.nativeElement.querySelector(
59
- "viking-field",
60
- ) as HTMLElement;
61
- expect(field.classList.contains("viking-field-invalid")).toBe(true);
62
- const alert = fixture.nativeElement.querySelector(
63
- ".viking-field-error",
64
- ) as HTMLElement;
65
- expect(alert.getAttribute("role")).toBe("alert");
66
- expect(alert.textContent).toContain("Invalid email address");
67
- });
68
-
69
- it("binds input value via ngModel (ControlValueAccessor)", async () => {
70
- const fixture = await render(FieldInputHost);
71
- const wc = fixture.nativeElement.querySelector(
72
- "viking-input-wc",
73
- ) as HTMLElement;
74
- const input = wc.shadowRoot?.querySelector("input") as HTMLInputElement;
75
- input.value = "ops@deml.app";
76
- input.dispatchEvent(new Event("input"));
77
- fixture.detectChanges();
78
- await fixture.whenStable();
79
- expect(fixture.componentInstance.email).toBe("ops@deml.app");
80
- });
81
-
82
- it("renders stacked form section with icon heading", async () => {
83
- const fixture = await render(FormStackHost);
84
- const section = fixture.nativeElement.querySelector(
85
- "viking-form-section",
86
- ) as HTMLElement;
87
- expect(section.classList.contains("viking-form-section-stack")).toBe(true);
88
- expect(
89
- section.querySelector(".viking-form-section-title")?.textContent,
90
- ).toContain("Profile");
91
- });
92
- });
@@ -1,85 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- } from "@angular/core";
7
-
8
- /** viking-gauge-arc — semicircle gauge fill driven by value / max. */
9
- @Component({
10
- selector: "viking-gauge-arc",
11
- changeDetection: ChangeDetectionStrategy.OnPush,
12
- host: {
13
- class: "viking-gauge-arc",
14
- "aria-hidden": "true",
15
- "[class.viking-gauge-arc-amber]": "tone() === 'amber'",
16
- "[class.viking-gauge-arc-danger]": "tone() === 'danger'",
17
- "[class.viking-gauge-arc-primary]": "tone() === 'primary'",
18
- },
19
- template: `
20
- <svg class="viking-gauge-arc-svg" viewBox="0 0 100 60" fill="none">
21
- <path class="viking-gauge-arc-bg" d="M10 50A40 40 0 0 1 90 50" />
22
- <path
23
- class="viking-gauge-arc-fill"
24
- d="M10 50A40 40 0 0 1 90 50"
25
- [attr.stroke-dasharray]="strokeDasharray()"
26
- />
27
- </svg>
28
- `,
29
- styles: [
30
- `
31
- :host {
32
- display: block;
33
- width: 100%;
34
- color: var(--viking-accent);
35
- }
36
-
37
- .viking-gauge-arc-svg {
38
- width: 100%;
39
- height: auto;
40
- overflow: visible;
41
- shape-rendering: geometricPrecision;
42
- }
43
-
44
- .viking-gauge-arc-bg,
45
- .viking-gauge-arc-fill {
46
- fill: none;
47
- stroke-width: 8;
48
- stroke-linecap: round;
49
- }
50
-
51
- .viking-gauge-arc-bg {
52
- stroke: color-mix(in srgb, var(--viking-text-muted) 25%, transparent);
53
- }
54
-
55
- .viking-gauge-arc-fill {
56
- stroke: currentColor;
57
- transition: stroke-dasharray 0.4s var(--viking-ease-default);
58
- }
59
-
60
- :host(.viking-gauge-arc-amber) {
61
- color: var(--viking-warning);
62
- }
63
-
64
- :host(.viking-gauge-arc-danger) {
65
- color: var(--viking-danger);
66
- }
67
-
68
- :host(.viking-gauge-arc-primary) {
69
- color: var(--viking-accent);
70
- }
71
- `,
72
- ],
73
- })
74
- export class VikingGaugeArc {
75
- readonly value = input.required<number>();
76
- readonly max = input<number>(100);
77
- readonly circumference = input<number>(125.66);
78
- readonly tone = input<"accent" | "amber" | "danger" | "primary">("accent");
79
-
80
- protected readonly strokeDasharray = computed(() => {
81
- const pct = Math.max(0, Math.min(1, this.value() / this.max()));
82
- const filled = pct * this.circumference();
83
- return `${filled} ${this.circumference()}`;
84
- });
85
- }
@@ -1,27 +0,0 @@
1
- import { ChangeDetectionStrategy, Component, input } from "@angular/core";
2
- import { VikingIcon } from "../icon/icon";
3
- import { VikingIconName } from "../../core/icons";
4
-
5
- /** viking-hud-panel — bordered dashboard panel with icon header. */
6
- @Component({
7
- selector: "viking-hud-panel",
8
- imports: [VikingIcon],
9
- changeDetection: ChangeDetectionStrategy.OnPush,
10
- host: {
11
- class: "viking-hud-panel panel-section",
12
- },
13
- template: `
14
- <div class="viking-hud-panel-header panel-header">
15
- @if (icon()) {
16
- <viking-icon [name]="icon()!" [size]="20" class="panel-icon" />
17
- }
18
- <h2 class="viking-hud-panel-title">{{ title() }}</h2>
19
- <ng-content select="[vikingHudPanelBadge]" />
20
- </div>
21
- <ng-content />
22
- `,
23
- })
24
- export class VikingHudPanel {
25
- readonly title = input.required<string>();
26
- readonly icon = input<VikingIconName | null>(null);
27
- }
@@ -1,284 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- } from "@angular/core";
7
- import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
8
- import {
9
- VIKING_FILLED_ICON_NAMES,
10
- VIKING_ICON_FILLED_PATHS,
11
- VIKING_ICON_PATHS,
12
- resolveVikingIcon,
13
- resolveVikingIconColor,
14
- resolveVikingIconSize,
15
- vikingIconViewBox,
16
- VikingIconColorToken,
17
- VikingIconName,
18
- VikingIconSizePreset,
19
- VikingIconVariant,
20
- VIKING_DRAKKAR_ICON_NAMES_LIST,
21
- } from "../../core/icons";
22
- import {
23
- isIntegrationBrandIcon,
24
- VIKING_INTEGRATION_BRAND_SVGS,
25
- type VikingIntegrationBrandName,
26
- } from "../../core/integration-brand-icons";
27
-
28
- const VIKING_FILLED_ICON_SET = new Set<string>(VIKING_FILLED_ICON_NAMES);
29
- const VIKING_DRAKKAR_ICON_SET = new Set<string>(VIKING_DRAKKAR_ICON_NAMES_LIST);
30
-
31
- /**
32
- * viking-icon — themeable inline SVG icon (Lucide-sourced registry + DEML brand marks).
33
- * Zero runtime dependencies; paths are inlined at build time from Lucide.
34
- *
35
- * @example Outline with semantic color
36
- * ```html
37
- * <viking-icon name="search" sizePreset="md" color="accent" />
38
- * ```
39
- *
40
- * @example Brand mark (outline)
41
- * ```html
42
- * <viking-icon name="drakkar" [size]="28" color="accent" />
43
- * ```
44
- */
45
- @Component({
46
- selector: "viking-icon",
47
- changeDetection: ChangeDetectionStrategy.OnPush,
48
- host: {
49
- "[class.viking-icon-spin]": "spin()",
50
- "[class.viking-icon-filled]": "isFilled()",
51
- "[class.viking-icon-outline]": "!isFilled()",
52
- "[class.viking-icon-brand-drakkar]": "isDrakkarBrand()",
53
- "[class.viking-icon-sm]": 'sizePreset() === "sm"',
54
- "[class.viking-icon-md]": 'sizePreset() === "md"',
55
- "[class.viking-icon-lg]":
56
- 'sizePreset() === "lg" || (!sizePreset() && !size())',
57
- "[class.viking-icon-backdrop]": "backdrop()",
58
- "[class.viking-icon-backdrop-success]":
59
- "backdrop() && backdropTone() === 'success'",
60
- "[class.viking-icon-backdrop-warning]":
61
- "backdrop() && backdropTone() === 'warning'",
62
- "[class.viking-icon-backdrop-danger]":
63
- "backdrop() && backdropTone() === 'danger'",
64
- "[class.viking-icon-backdrop-info]":
65
- "backdrop() && backdropTone() === 'info'",
66
- "[style.color]": "resolvedColor()",
67
- "aria-hidden": "true",
68
- },
69
- template: `
70
- @if (resolvedName() === "google") {
71
- <svg
72
- class="viking-icon-svg viking-icon-brand"
73
- xmlns="http://www.w3.org/2000/svg"
74
- viewBox="0 0 48 48"
75
- [style.width.px]="resolvedSize()"
76
- [style.height.px]="resolvedSize()"
77
- aria-hidden="true"
78
- >
79
- <path
80
- fill="#EA4335"
81
- d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
82
- />
83
- <path
84
- fill="#4285F4"
85
- d="M46.5 24c0-1.55-.15-3.24-.47-4.77H24v9.03h12.75c-.55 2.83-2.13 5.23-4.53 6.82l7.02 5.44C43.35 36.56 46.5 30.82 46.5 24z"
86
- />
87
- <path
88
- fill="#FBBC05"
89
- d="M10.54 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24s.92 7.54 2.56 10.78l7.98-6.19z"
90
- />
91
- <path
92
- fill="#34A853"
93
- d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.02-5.44c-1.99 1.33-4.51 2.15-7.87 2.15-6.26 0-11.57-4.22-13.46-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"
94
- />
95
- </svg>
96
- } @else if (resolvedName() === "apple") {
97
- <svg
98
- class="viking-icon-svg viking-icon-brand"
99
- xmlns="http://www.w3.org/2000/svg"
100
- viewBox="0 0 24 24"
101
- fill="currentColor"
102
- [style.width.px]="resolvedSize()"
103
- [style.height.px]="resolvedSize()"
104
- aria-hidden="true"
105
- >
106
- <path
107
- d="M16.365 12.14c.02 2.53 2.21 3.38 2.23 3.39-.02.07-.35 1.21-1.16 2.4-.7 1.02-1.43 2.03-2.58 2.05-1.13.02-1.49-.67-2.78-.67-1.29 0-1.69.65-2.75.69-1.11.04-1.95-1.12-2.66-2.13-1.44-2.08-2.54-5.87-1.07-8.43.73-1.27 2.04-2.08 3.46-2.1 1.08-.02 2.1.72 2.78.72.67 0 2.14-.89 3.61-.76.61.03 2.33.25 3.44 1.88-.09.06-2.05 1.2-2.03 3.55M13.75 3.64c.59-.71 1-1.7.89-2.68-.86.03-1.9.57-2.52 1.28-.55.63-1.03 1.65-.9 2.62.95.07 1.92-.49 2.53-1.22"
108
- />
109
- </svg>
110
- } @else if (isIntegrationBrand()) {
111
- <svg
112
- class="viking-icon-svg viking-icon-brand viking-icon-integration-brand"
113
- xmlns="http://www.w3.org/2000/svg"
114
- viewBox="0 0 24 24"
115
- [style.width.px]="resolvedSize()"
116
- [style.height.px]="resolvedSize()"
117
- aria-hidden="true"
118
- >
119
- <g [innerHTML]="integrationBrandSvg()"></g>
120
- </svg>
121
- } @else {
122
- <svg
123
- class="viking-icon-svg"
124
- xmlns="http://www.w3.org/2000/svg"
125
- [attr.viewBox]="viewBox()"
126
- [attr.fill]="isFilled() ? 'currentColor' : 'none'"
127
- [attr.fill-rule]="isFilled() ? 'evenodd' : null"
128
- [attr.stroke]="isFilled() ? 'none' : 'currentColor'"
129
- stroke-linecap="round"
130
- stroke-linejoin="round"
131
- [style.width.px]="resolvedSize()"
132
- [style.height.px]="resolvedSize()"
133
- >
134
- <!-- innerHTML on <g> — binding on <svg> throws NotYetImplemented under SSR (domino). -->
135
- <g [innerHTML]="paths()"></g>
136
- </svg>
137
- }
138
- `,
139
- styles: [
140
- `
141
- :host {
142
- display: inline-flex;
143
- align-items: center;
144
- justify-content: center;
145
- flex-shrink: 0;
146
- line-height: 0;
147
- color: inherit;
148
- }
149
-
150
- :host(.viking-icon-outline) .viking-icon-svg {
151
- --viking-icon-stroke-width: 1.75;
152
- stroke-width: var(--viking-icon-stroke-width);
153
- shape-rendering: geometricPrecision;
154
- }
155
-
156
- :host(.viking-icon-outline.viking-icon-brand-drakkar) .viking-icon-svg {
157
- --viking-icon-stroke-width: 1.5;
158
- }
159
-
160
- :host(.viking-icon-sm) .viking-icon-svg {
161
- --viking-icon-stroke-width: 1.5;
162
- }
163
-
164
- :host(.viking-icon-lg) .viking-icon-svg {
165
- --viking-icon-stroke-width: 1.75;
166
- }
167
-
168
- :host(.viking-icon-filled) .viking-icon-svg {
169
- stroke: none;
170
- }
171
-
172
- :host(.viking-icon-spin) svg {
173
- animation: viking-icon-rotate 0.9s linear infinite;
174
- }
175
-
176
- :host(.viking-icon-backdrop) {
177
- padding: var(--viking-icon-backdrop-padding, var(--viking-space-half));
178
- border-radius: var(--viking-radius-lg);
179
- background: var(--viking-accent-soft);
180
- color: var(--viking-accent-strong);
181
- box-shadow: var(--viking-shadow-sm);
182
- }
183
-
184
- :host(.viking-icon-backdrop-success) {
185
- background: color-mix(in srgb, var(--viking-success) 14%, transparent);
186
- color: var(--viking-success);
187
- }
188
-
189
- :host(.viking-icon-backdrop-warning) {
190
- background: color-mix(in srgb, var(--viking-warning) 14%, transparent);
191
- color: var(--viking-warning);
192
- }
193
-
194
- :host(.viking-icon-backdrop-danger) {
195
- background: color-mix(in srgb, var(--viking-danger) 14%, transparent);
196
- color: var(--viking-danger);
197
- }
198
-
199
- :host(.viking-icon-backdrop-info) {
200
- background: color-mix(in srgb, var(--viking-info) 14%, transparent);
201
- color: var(--viking-info);
202
- }
203
-
204
- @keyframes viking-icon-rotate {
205
- to {
206
- transform: rotate(360deg);
207
- }
208
- }
209
- `,
210
- ],
211
- })
212
- export class VikingIcon {
213
- readonly name = input.required<VikingIconName | string>();
214
- /** Explicit pixel size — overridden by sizePreset when set. */
215
- readonly size = input<number | undefined>(undefined);
216
- /** sm (16px) · md (20px) · lg (24px) */
217
- readonly sizePreset = input<VikingIconSizePreset | null>(null);
218
- /** outline (stroke) or filled (solid) */
219
- readonly variant = input<VikingIconVariant>("outline");
220
- /** Semantic token (accent, success, …) or any CSS color value. */
221
- readonly color = input<VikingIconColorToken | string | undefined>(undefined);
222
- /** Renders icon inside a padded tokenized backdrop (matches viking-icon-badge). */
223
- readonly backdrop = input<boolean>(false);
224
- readonly backdropTone = input<
225
- "default" | "success" | "warning" | "danger" | "info"
226
- >("default");
227
- readonly spin = input<boolean>(false);
228
-
229
- protected readonly resolvedName = computed(() =>
230
- resolveVikingIcon(this.name()),
231
- );
232
-
233
- protected readonly resolvedSize = computed(() =>
234
- resolveVikingIconSize(this.size(), this.sizePreset()),
235
- );
236
-
237
- protected readonly resolvedColor = computed(() =>
238
- resolveVikingIconColor(this.color()),
239
- );
240
-
241
- protected readonly viewBox = computed(() =>
242
- vikingIconViewBox(this.resolvedName()),
243
- );
244
-
245
- protected readonly isFilled = computed(() => {
246
- const name = this.resolvedName();
247
- if (name === "google" || name === "apple" || isIntegrationBrandIcon(name)) {
248
- return false;
249
- }
250
- if (this.variant() === "filled") {
251
- return true;
252
- }
253
- return VIKING_FILLED_ICON_SET.has(name);
254
- });
255
-
256
- protected readonly isDrakkarBrand = computed(() =>
257
- VIKING_DRAKKAR_ICON_SET.has(this.resolvedName()),
258
- );
259
-
260
- protected readonly isIntegrationBrand = computed(() =>
261
- isIntegrationBrandIcon(this.resolvedName()),
262
- );
263
-
264
- protected readonly integrationBrandSvg = computed<SafeHtml>(() => {
265
- const name = this.resolvedName() as VikingIntegrationBrandName;
266
- return this.sanitizer.bypassSecurityTrustHtml(
267
- VIKING_INTEGRATION_BRAND_SVGS[name] ?? "",
268
- );
269
- });
270
-
271
- protected readonly paths = computed<SafeHtml>(() => {
272
- const name = this.resolvedName();
273
- const html =
274
- this.isFilled() && VIKING_ICON_FILLED_PATHS[name]
275
- ? VIKING_ICON_FILLED_PATHS[name]
276
- : (VIKING_ICON_PATHS[name] ?? "");
277
- return this.sanitizer.bypassSecurityTrustHtml(html);
278
- });
279
-
280
- constructor(private readonly sanitizer: DomSanitizer) {}
281
- }
282
-
283
- /** Alias for consumers expecting VikingIconComponent. */
284
- export { VikingIcon as VikingIconComponent };
@@ -1,87 +0,0 @@
1
- import { ChangeDetectionStrategy, Component, input } from "@angular/core";
2
- import { VikingIcon } from "../icon/icon";
3
- import {
4
- VikingIconColorToken,
5
- VikingIconName,
6
- VikingIconSizePreset,
7
- } from "../../core/icons";
8
-
9
- export type VikingIconBadgeTone =
10
- | "default"
11
- | "success"
12
- | "warning"
13
- | "danger"
14
- | "info";
15
-
16
- /**
17
- * viking-icon-badge — consistent icon backdrop for empty states, callouts, and metric headers.
18
- */
19
- @Component({
20
- selector: "viking-icon-badge",
21
- imports: [VikingIcon],
22
- changeDetection: ChangeDetectionStrategy.OnPush,
23
- host: {
24
- class: "viking-icon-badge",
25
- "[class.viking-icon-badge-success]": "tone() === 'success'",
26
- "[class.viking-icon-badge-warning]": "tone() === 'warning'",
27
- "[class.viking-icon-badge-danger]": "tone() === 'danger'",
28
- "[class.viking-icon-badge-info]": "tone() === 'info'",
29
- "[attr.aria-hidden]": 'decorative() ? "true" : null',
30
- },
31
- template: `
32
- <viking-icon
33
- [name]="icon()"
34
- [size]="size()"
35
- [sizePreset]="sizePreset()"
36
- [color]="color()"
37
- [variant]="variant()"
38
- />
39
- `,
40
- styles: [
41
- `
42
- :host {
43
- display: inline-flex;
44
- align-items: center;
45
- justify-content: center;
46
- flex-shrink: 0;
47
- width: var(--viking-icon-badge-size, var(--viking-space-6));
48
- height: var(--viking-icon-badge-size, var(--viking-space-6));
49
- padding: var(--viking-icon-badge-padding, var(--viking-space-half));
50
- box-sizing: border-box;
51
- border-radius: var(--viking-radius-lg);
52
- background: var(--viking-accent-soft);
53
- color: var(--viking-accent-strong);
54
- box-shadow: var(--viking-shadow-sm);
55
- }
56
-
57
- :host(.viking-icon-badge-success) {
58
- background: color-mix(in srgb, var(--viking-success) 14%, transparent);
59
- color: var(--viking-success);
60
- }
61
-
62
- :host(.viking-icon-badge-warning) {
63
- background: color-mix(in srgb, var(--viking-warning) 14%, transparent);
64
- color: var(--viking-warning);
65
- }
66
-
67
- :host(.viking-icon-badge-danger) {
68
- background: color-mix(in srgb, var(--viking-danger) 14%, transparent);
69
- color: var(--viking-danger);
70
- }
71
-
72
- :host(.viking-icon-badge-info) {
73
- background: color-mix(in srgb, var(--viking-info) 14%, transparent);
74
- color: var(--viking-info);
75
- }
76
- `,
77
- ],
78
- })
79
- export class VikingIconBadge {
80
- readonly icon = input.required<VikingIconName>();
81
- readonly tone = input<VikingIconBadgeTone>("default");
82
- readonly size = input<number | undefined>(28);
83
- readonly sizePreset = input<VikingIconSizePreset | null>(null);
84
- readonly color = input<VikingIconColorToken | string | undefined>(undefined);
85
- readonly variant = input<"outline" | "filled">("outline");
86
- readonly decorative = input<boolean>(true);
87
- }
@@ -1,32 +0,0 @@
1
- import { Component } from "@angular/core";
2
- import { TestBed } from "@angular/core/testing";
3
- import { VikingIconHeading } from "./icon-heading";
4
-
5
- @Component({
6
- imports: [VikingIconHeading],
7
- template: `<viking-icon-heading icon="shield" headingLevel="h3"
8
- >Tenant Isolation</viking-icon-heading
9
- >`,
10
- })
11
- class HostComponent {}
12
-
13
- describe("VikingIconHeading", () => {
14
- beforeEach(async () => {
15
- await TestBed.configureTestingModule({
16
- imports: [HostComponent],
17
- }).compileComponents();
18
- });
19
-
20
- it("renders aligned icon and title", () => {
21
- const fixture = TestBed.createComponent(HostComponent);
22
- fixture.detectChanges();
23
- const heading = fixture.nativeElement.querySelector(
24
- ".viking-icon-heading",
25
- ) as HTMLElement;
26
- expect(heading).toBeTruthy();
27
- expect(heading.querySelector(".viking-icon-heading__icon")).toBeTruthy();
28
- expect(
29
- heading.querySelector("h3.viking-icon-heading__title")?.textContent,
30
- ).toContain("Tenant Isolation");
31
- });
32
- });
@@ -1,38 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- ViewEncapsulation,
5
- input,
6
- } from "@angular/core";
7
- import { VikingIcon } from "../icon/icon";
8
- import { VikingIconName } from "../../core/icons";
9
-
10
- /**
11
- * viking-icon-heading — icon + title row with shared vertical alignment.
12
- * Use in bento cards, integration tiles, and docs panels.
13
- */
14
- @Component({
15
- selector: "viking-icon-heading",
16
- changeDetection: ChangeDetectionStrategy.OnPush,
17
- encapsulation: ViewEncapsulation.None,
18
- imports: [VikingIcon],
19
- host: {
20
- class: "viking-icon-heading",
21
- "[class.viking-icon-heading--lg]": 'size() === "lg"',
22
- },
23
- template: `
24
- <span class="viking-icon-heading__icon" aria-hidden="true">
25
- <viking-icon [name]="icon()" [size]="24" color="accent" />
26
- </span>
27
- @if (headingLevel() === "h2") {
28
- <h2 class="viking-icon-heading__title"><ng-content /></h2>
29
- } @else {
30
- <h3 class="viking-icon-heading__title"><ng-content /></h3>
31
- }
32
- `,
33
- })
34
- export class VikingIconHeading {
35
- readonly icon = input.required<VikingIconName>();
36
- readonly size = input<"md" | "lg">("md");
37
- readonly headingLevel = input<"h2" | "h3">("h3");
38
- }