@dataengineeringformachinelearning/viking-ui 1.0.2 → 3.0.0-alpha.2

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 (129) hide show
  1. package/README.md +180 -41
  2. package/dist/deml-components.css +1122 -0
  3. package/dist/design-tokens.css +688 -0
  4. package/dist/elements/button/viking-button.d.ts +14 -0
  5. package/dist/elements/card/viking-card.d.ts +8 -0
  6. package/dist/elements/core/dom.d.ts +4 -0
  7. package/dist/elements/core/styles.d.ts +2 -0
  8. package/dist/elements/modal/viking-modal.d.ts +15 -0
  9. package/dist/fonts/inter/InterVariable-Italic.woff2 +0 -0
  10. package/dist/fonts/inter/InterVariable.woff2 +0 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +4051 -0
  13. package/dist/lib/core/brand-icons.d.ts +29 -0
  14. package/dist/lib/core/icons.d.ts +132 -0
  15. package/dist/lib/core/integration-brand-icons.d.ts +18 -0
  16. package/dist/lib/core/lucide-paths.generated.d.ts +90 -0
  17. package/dist/lib/site-drakkar/site-drakkar.config.d.ts +50 -0
  18. package/dist/lib/site-drakkar/suite-search-items.d.ts +17 -0
  19. package/dist/viking-components.css +1837 -0
  20. package/dist/viking-tokens.json +318 -0
  21. package/dist/viking-ui-elements.js +1750 -0
  22. package/dist/viking-ui.css +1 -0
  23. package/dist/web/badge/viking-badge-wc.d.ts +28 -0
  24. package/dist/web/button/viking-button-wc.d.ts +28 -0
  25. package/dist/web/callout/viking-callout-wc.d.ts +27 -0
  26. package/dist/web/card/viking-card-wc.d.ts +29 -0
  27. package/dist/web/core/base.d.ts +12 -0
  28. package/dist/web/core/dom.d.ts +11 -0
  29. package/dist/web/core/icons-inline.d.ts +7 -0
  30. package/dist/web/core/styles.d.ts +12 -0
  31. package/dist/web/core/types.d.ts +10 -0
  32. package/dist/web/field/viking-field-wc.d.ts +32 -0
  33. package/dist/web/index.d.ts +15 -0
  34. package/dist/web/input/viking-input-wc.d.ts +32 -0
  35. package/dist/web/modal/viking-modal-wc.d.ts +50 -0
  36. package/dist/web/search-palette/viking-search-palette-wc.d.ts +64 -0
  37. package/dist/web/select/viking-select-wc.d.ts +48 -0
  38. package/dist/web/suite-header/viking-suite-header-wc.d.ts +36 -0
  39. package/dist/web/suite-search-palette/viking-suite-search-palette-wc.d.ts +39 -0
  40. package/dist/web/theme-toggle/viking-theme-toggle-wc.d.ts +19 -0
  41. package/dist/web/types.d.ts +40 -0
  42. package/dist/web-components/index.d.ts +1 -0
  43. package/dist/web-components.js +1750 -0
  44. package/dist/widget.js +1182 -0
  45. package/package.json +89 -30
  46. package/src/assets/fonts/inter/InterVariable-Italic.woff2 +0 -0
  47. package/src/assets/fonts/inter/InterVariable.woff2 +0 -0
  48. package/src/elements/button/viking-button.ts +201 -0
  49. package/src/elements/card/viking-card.ts +60 -0
  50. package/src/elements/core/dom.ts +33 -0
  51. package/src/elements/core/styles.ts +28 -0
  52. package/src/elements/modal/viking-modal.ts +154 -0
  53. package/src/index.ts +1 -0
  54. package/src/lib/core/brand-icons.ts +62 -0
  55. package/src/lib/core/icons.ts +206 -0
  56. package/src/lib/core/integration-brand-icons.ts +77 -0
  57. package/src/lib/core/lucide-paths.generated.ts +130 -0
  58. package/src/lib/site-drakkar/site-drakkar.config.ts +295 -0
  59. package/src/lib/site-drakkar/suite-search-items.ts +246 -0
  60. package/src/styles/_buttons.scss +301 -0
  61. package/src/styles/_component-primitives.scss +183 -0
  62. package/src/styles/_drakkar-buttons.scss +85 -0
  63. package/src/styles/_fonts.scss +22 -0
  64. package/src/styles/_forms.scss +66 -0
  65. package/src/styles/_input.scss +106 -0
  66. package/src/styles/_layout-enforcement.scss +166 -0
  67. package/src/styles/_layout-rhythm.scss +158 -0
  68. package/src/styles/_legacy-aliases.scss +212 -0
  69. package/src/styles/_series-colors.scss +24 -0
  70. package/src/styles/_static-primitives.scss +857 -0
  71. package/src/styles/_typography.scss +87 -0
  72. package/src/styles/_variables.scss +527 -0
  73. package/src/styles/components/a11y.scss +90 -0
  74. package/src/styles/components/badges.scss +102 -0
  75. package/src/styles/components/extracted-utilities.scss +459 -0
  76. package/src/styles/components/footer.scss +155 -0
  77. package/src/styles/components/icon-heading.scss +47 -0
  78. package/src/styles/components/icon-inline.scss +78 -0
  79. package/src/styles/components/layout.scss +59 -0
  80. package/src/styles/components/utilities.scss +131 -0
  81. package/src/styles/components/viking-inspired.scss +204 -0
  82. package/src/styles/components/whitepaper-cta.scss +130 -0
  83. package/src/styles/components-bundle.scss +9 -0
  84. package/src/styles/components.scss +175 -0
  85. package/src/styles/deml-components.scss +10 -0
  86. package/src/styles/index.scss +8 -0
  87. package/src/styles/layout-shell.scss +39 -11
  88. package/src/styles/page-shell.scss +663 -33
  89. package/src/styles/static-navbar.scss +862 -146
  90. package/src/styles/surfaces/backend.scss +142 -0
  91. package/src/styles/surfaces/docs-global.scss +73 -0
  92. package/src/styles/surfaces/docs-shell.scss +412 -0
  93. package/src/styles/surfaces/docs-showcase.scss +1051 -0
  94. package/src/styles/surfaces/marketing-cta.scss +62 -0
  95. package/src/styles/surfaces/marketing-docs-bento.scss +67 -0
  96. package/src/styles/surfaces/marketing-global.scss +748 -0
  97. package/src/styles/surfaces/marketing-landing.scss +1260 -0
  98. package/src/styles/surfaces/marketing-publication.scss +535 -0
  99. package/src/styles/surfaces/marketing-theme.scss +14 -0
  100. package/src/styles/surfaces/swagger-ui.scss +921 -0
  101. package/src/styles/tokens-export.scss +18 -0
  102. package/src/styles/tokens.scss +5 -0
  103. package/src/styles/viking-ui-bundle.scss +20 -2
  104. package/src/styles/viking-ui.scss +213 -51
  105. package/src/tokens/viking-tokens.json +318 -0
  106. package/src/web/badge/viking-badge-wc.ts +116 -0
  107. package/src/web/button/viking-button-wc.ts +165 -0
  108. package/src/web/callout/viking-callout-wc.ts +105 -0
  109. package/src/web/card/viking-card-wc.ts +66 -0
  110. package/src/web/core/base.ts +56 -0
  111. package/src/web/core/dom.ts +53 -0
  112. package/src/web/core/icons-inline.ts +44 -0
  113. package/src/web/core/styles.ts +1138 -0
  114. package/src/web/core/types.ts +19 -0
  115. package/src/web/field/viking-field-wc.ts +154 -0
  116. package/src/web/index.ts +73 -0
  117. package/src/web/input/viking-input-wc.ts +211 -0
  118. package/src/web/modal/viking-modal-wc.ts +187 -0
  119. package/src/web/search-palette/viking-search-palette-wc.ts +494 -0
  120. package/src/web/select/viking-select-wc.ts +218 -0
  121. package/src/web/suite-header/viking-suite-header-wc.ts +714 -0
  122. package/src/web/suite-search-palette/viking-suite-search-palette-wc.ts +234 -0
  123. package/src/web/theme-toggle/viking-theme-toggle-wc.ts +139 -0
  124. package/src/web/types.ts +37 -0
  125. package/src/web-components/index.ts +1 -0
  126. package/fesm2022/dataengineeringformachinelearning-viking-ui.mjs +0 -6114
  127. package/fesm2022/dataengineeringformachinelearning-viking-ui.mjs.map +0 -1
  128. package/types/dataengineeringformachinelearning-viking-ui.d.ts +0 -1397
  129. package/viking.manifest.json +0 -238
package/package.json CHANGED
@@ -1,38 +1,97 @@
1
1
  {
2
2
  "name": "@dataengineeringformachinelearning/viking-ui",
3
- "version": "1.0.2",
4
- "description": "Viking-UI: DEML clinical design system for Angular. THEME.md palette, WCAG 2.1 AA, zero third-party UI runtime deps.",
5
- "keywords": [
6
- "angular",
7
- "ui",
8
- "viking-ui",
9
- "design-system",
10
- "deml",
11
- "a11y"
12
- ],
13
- "license": "UNLICENSED",
3
+ "version": "3.0.0-alpha.2",
4
+ "description": "Universal Viking-UI design system for Astro, Angular, and Django.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "private": false,
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "style": "./dist/viking-ui.css",
12
+ "browser": "./dist/viking-ui-elements.js",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/dataengineeringformachinelearning/dataengineeringformachinelearning.git",
16
+ "directory": "packages/viking-ui"
17
+ },
14
18
  "publishConfig": {
15
19
  "access": "public"
16
20
  },
17
- "peerDependencies": {
18
- "@angular/common": "^22.0.0",
19
- "@angular/core": "^22.0.0",
20
- "@angular/forms": "^22.0.0"
21
- },
22
- "dependencies": {
23
- "tslib": "^2.3.0"
24
- },
25
- "sideEffects": false,
26
- "module": "fesm2022/dataengineeringformachinelearning-viking-ui.mjs",
27
- "typings": "types/dataengineeringformachinelearning-viking-ui.d.ts",
28
21
  "exports": {
29
- "./package.json": {
30
- "default": "./package.json"
31
- },
32
22
  ".": {
33
- "types": "./types/dataengineeringformachinelearning-viking-ui.d.ts",
34
- "default": "./fesm2022/dataengineeringformachinelearning-viking-ui.mjs"
35
- }
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ },
26
+ "./dist/index.js": "./dist/index.js",
27
+ "./dist/viking-ui.css": "./dist/viking-ui.css",
28
+ "./dist/viking-ui-elements.js": "./dist/viking-ui-elements.js",
29
+ "./dist/web-components.js": "./dist/web-components.js",
30
+ "./dist/widget.js": "./dist/widget.js",
31
+ "./elements": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/web-components.js",
34
+ "default": "./dist/web-components.js"
35
+ },
36
+ "./elements.js": "./dist/viking-ui-elements.js",
37
+ "./viking-ui-elements.js": "./dist/viking-ui-elements.js",
38
+ "./web-components.js": "./dist/web-components.js",
39
+ "./web-components": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/web-components.js",
42
+ "default": "./dist/web-components.js"
43
+ },
44
+ "./css": "./dist/viking-ui.css",
45
+ "./css/index.css": "./dist/viking-ui.css",
46
+ "./css/viking-ui.css": "./dist/viking-ui.css",
47
+ "./css/design-tokens.css": "./dist/design-tokens.css",
48
+ "./css/viking-components.css": "./dist/viking-components.css",
49
+ "./css/deml-components.css": "./dist/deml-components.css",
50
+ "./css/tokens.css": "./dist/design-tokens.css",
51
+ "./css/components.css": "./dist/viking-components.css",
52
+ "./design-tokens.css": "./dist/design-tokens.css",
53
+ "./tokens.css": "./dist/design-tokens.css",
54
+ "./tokens": "./dist/viking-tokens.json",
55
+ "./tokens.json": "./dist/viking-tokens.json",
56
+ "./viking-tokens.json": "./dist/viking-tokens.json",
57
+ "./components.css": "./dist/viking-components.css",
58
+ "./deml-components.css": "./dist/deml-components.css",
59
+ "./viking-ui.css": "./dist/viking-ui.css",
60
+ "./package.json": "./package.json"
36
61
  },
37
- "type": "module"
38
- }
62
+ "files": [
63
+ "dist",
64
+ "src",
65
+ "README.md"
66
+ ],
67
+ "scripts": {
68
+ "clean": "rm -rf dist",
69
+ "build": "npm run clean && npm run build:css && npm run build:elements",
70
+ "build:css": "node scripts/build-css.mjs",
71
+ "build:elements": "node scripts/build-elements.mjs",
72
+ "storybook": "npm run build:css && storybook dev --config-dir .storybook --port 6006",
73
+ "build-storybook": "npm run build:css && storybook build --config-dir .storybook --output-dir ./storybook-static",
74
+ "chromatic": "npm run build-storybook && chromatic --project-token=${CHROMATIC_PROJECT_TOKEN} --exit-zero-on-changes",
75
+ "validate": "node ../../scripts/validate_viking_ui_assets.mjs",
76
+ "test": "node --test test/*.test.mjs",
77
+ "pack:check": "npm pack --dry-run",
78
+ "typecheck": "tsc --project tsconfig.json --noEmit"
79
+ },
80
+ "sideEffects": [
81
+ "./dist/viking-ui-elements.js",
82
+ "./dist/viking-ui.css",
83
+ "./dist/design-tokens.css",
84
+ "./dist/viking-components.css",
85
+ "./dist/deml-components.css",
86
+ "./src/index.ts"
87
+ ],
88
+ "devDependencies": {
89
+ "@chromatic-com/storybook": "^3.2.7",
90
+ "@storybook/addon-a11y": "^8.6.12",
91
+ "@storybook/addon-essentials": "^8.6.12",
92
+ "@storybook/html": "^8.6.12",
93
+ "esbuild": "^0.28.1",
94
+ "sass": "^1.101.0",
95
+ "typescript": "~6.0.3"
96
+ }
97
+ }
@@ -0,0 +1,201 @@
1
+ import {
2
+ attributeValue,
3
+ defineVikingElement,
4
+ HTMLElementBase,
5
+ readBooleanAttribute,
6
+ } from "../core/dom";
7
+ import { attachStyles, resetStyles } from "../core/styles";
8
+
9
+ const variants = new Set([
10
+ "outline",
11
+ "primary",
12
+ "secondary",
13
+ "danger",
14
+ "ghost",
15
+ ]);
16
+ const sizes = new Set(["sm", "md"]);
17
+
18
+ const styles = `
19
+ ${resetStyles}
20
+
21
+ :host {
22
+ display: inline-flex;
23
+ }
24
+
25
+ :host([full-width]) {
26
+ display: flex;
27
+ width: 100%;
28
+ }
29
+
30
+ .control {
31
+ display: inline-flex;
32
+ width: auto;
33
+ min-width: var(--viking-btn-min-width, 120px);
34
+ min-height: var(--viking-control-height);
35
+ align-items: center;
36
+ justify-content: center;
37
+ gap: var(--viking-space-1);
38
+ padding: 0 var(--viking-control-padding-x);
39
+ border: 1px solid var(--viking-border-strong);
40
+ border-radius: var(--viking-radius);
41
+ background: var(--viking-surface);
42
+ color: var(--viking-text);
43
+ box-shadow: var(--viking-shadow-sm);
44
+ cursor: pointer;
45
+ font: inherit;
46
+ font-size: var(--viking-font-size-sm);
47
+ font-weight: var(--viking-font-weight-semibold);
48
+ letter-spacing: var(--viking-letter-spacing-wide);
49
+ line-height: var(--viking-line-height-snug);
50
+ text-decoration: none;
51
+ transition: var(--viking-transition-interactive);
52
+ user-select: none;
53
+ white-space: nowrap;
54
+ }
55
+
56
+ :host([full-width]) .control {
57
+ width: 100%;
58
+ }
59
+
60
+ .control:hover:not(:disabled):not([aria-busy='true']) {
61
+ border-color: color-mix(in srgb, var(--viking-accent) 45%, var(--viking-border-strong));
62
+ transform: translateY(var(--viking-state-hover-lift));
63
+ }
64
+
65
+ .control:focus-visible {
66
+ outline: var(--viking-ring-width) solid var(--viking-ring);
67
+ outline-offset: var(--viking-ring-offset);
68
+ }
69
+
70
+ .control:disabled,
71
+ .control[aria-busy='true'] {
72
+ cursor: not-allowed;
73
+ opacity: var(--viking-state-disabled-opacity);
74
+ transform: none;
75
+ }
76
+
77
+ .control[data-size='sm'] {
78
+ min-height: var(--viking-control-height-sm);
79
+ min-width: auto;
80
+ padding-inline: var(--viking-space-2);
81
+ }
82
+
83
+ .control[data-variant='primary'] {
84
+ border-color: color-mix(in srgb, var(--viking-accent) 82%, var(--viking-black));
85
+ background: var(--viking-accent);
86
+ color: var(--viking-accent-content);
87
+ }
88
+
89
+ .control[data-variant='secondary'] {
90
+ border-color: color-mix(in srgb, var(--viking-accent-secondary) 82%, var(--viking-black));
91
+ background: var(--viking-accent-secondary);
92
+ color: var(--viking-accent-secondary-content);
93
+ }
94
+
95
+ .control[data-variant='danger'] {
96
+ border-color: color-mix(in srgb, var(--viking-danger) 82%, var(--viking-black));
97
+ background: var(--viking-danger);
98
+ color: var(--viking-on-danger);
99
+ }
100
+
101
+ .control[data-variant='ghost'] {
102
+ min-width: auto;
103
+ border-color: transparent;
104
+ background: transparent;
105
+ box-shadow: none;
106
+ }
107
+ `;
108
+
109
+ export class VikingButton extends HTMLElementBase {
110
+ static readonly tagName = "viking-button";
111
+
112
+ static get observedAttributes(): string[] {
113
+ return [
114
+ "variant",
115
+ "size",
116
+ "type",
117
+ "href",
118
+ "target",
119
+ "disabled",
120
+ "loading",
121
+ "aria-label",
122
+ ];
123
+ }
124
+
125
+ private readonly shadowRootRef: ShadowRoot;
126
+ private control: HTMLAnchorElement | HTMLButtonElement | null = null;
127
+
128
+ constructor() {
129
+ super();
130
+ this.shadowRootRef = this.attachShadow({ mode: "open" });
131
+ attachStyles(this.shadowRootRef, styles);
132
+ }
133
+
134
+ connectedCallback(): void {
135
+ this.render();
136
+ this.control?.addEventListener("click", this.handleClick);
137
+ }
138
+
139
+ disconnectedCallback(): void {
140
+ this.control?.removeEventListener("click", this.handleClick);
141
+ }
142
+
143
+ attributeChangedCallback(): void {
144
+ if (this.isConnected) {
145
+ this.render();
146
+ }
147
+ }
148
+
149
+ private readonly handleClick = (event: Event): void => {
150
+ if (
151
+ readBooleanAttribute(this, "disabled") ||
152
+ readBooleanAttribute(this, "loading")
153
+ ) {
154
+ event.preventDefault();
155
+ event.stopPropagation();
156
+ return;
157
+ }
158
+
159
+ this.dispatchEvent(
160
+ new CustomEvent("viking-press", {
161
+ bubbles: true,
162
+ composed: true,
163
+ detail: { sourceEvent: event },
164
+ }),
165
+ );
166
+ };
167
+
168
+ private render(): void {
169
+ const href = this.getAttribute("href");
170
+ const tag = href ? "a" : "button";
171
+ const variant = attributeValue(this, "variant", "outline", variants);
172
+ const size = attributeValue(this, "size", "md", sizes);
173
+ const disabled =
174
+ readBooleanAttribute(this, "disabled") ||
175
+ readBooleanAttribute(this, "loading");
176
+ const label = this.getAttribute("aria-label");
177
+ const target = this.getAttribute("target");
178
+
179
+ this.shadowRootRef.innerHTML = `
180
+ <${tag}
181
+ part="control"
182
+ class="control"
183
+ data-variant="${variant}"
184
+ data-size="${size}"
185
+ ${href ? `href="${href}"` : `type="${this.getAttribute("type") ?? "button"}"`}
186
+ ${target ? `target="${target}"` : ""}
187
+ ${target === "_blank" ? 'rel="noopener noreferrer"' : ""}
188
+ ${disabled ? 'disabled aria-disabled="true"' : ""}
189
+ ${readBooleanAttribute(this, "loading") ? 'aria-busy="true"' : ""}
190
+ ${label ? `aria-label="${label}"` : ""}
191
+ >
192
+ <slot></slot>
193
+ </${tag}>
194
+ `;
195
+ this.control = this.shadowRootRef.querySelector(tag);
196
+ }
197
+ }
198
+
199
+ export const registerVikingButton = (): void => {
200
+ defineVikingElement(VikingButton.tagName, VikingButton);
201
+ };
@@ -0,0 +1,60 @@
1
+ import { defineVikingElement, HTMLElementBase } from "../core/dom";
2
+ import { attachStyles, resetStyles } from "../core/styles";
3
+
4
+ const styles = `
5
+ ${resetStyles}
6
+
7
+ :host {
8
+ display: block;
9
+ }
10
+
11
+ .card {
12
+ display: grid;
13
+ gap: var(--viking-space-2);
14
+ padding: var(--viking-card-padding);
15
+ border: 1px solid var(--viking-border);
16
+ border-radius: var(--viking-radius-lg);
17
+ background: var(--viking-surface-recipe);
18
+ color: var(--viking-text);
19
+ box-shadow: var(--viking-shadow-sm);
20
+ }
21
+
22
+ :host([compact]) .card {
23
+ padding: var(--viking-card-padding-compact);
24
+ }
25
+
26
+ ::slotted([slot='header']) {
27
+ color: var(--viking-text);
28
+ font-weight: var(--viking-font-weight-semibold);
29
+ }
30
+
31
+ ::slotted([slot='footer']) {
32
+ color: var(--viking-text-muted);
33
+ }
34
+ `;
35
+
36
+ export class VikingCard extends HTMLElementBase {
37
+ static readonly tagName = "viking-card";
38
+
39
+ private readonly shadowRootRef: ShadowRoot;
40
+
41
+ constructor() {
42
+ super();
43
+ this.shadowRootRef = this.attachShadow({ mode: "open" });
44
+ attachStyles(this.shadowRootRef, styles);
45
+ }
46
+
47
+ connectedCallback(): void {
48
+ this.shadowRootRef.innerHTML = `
49
+ <article class="card" part="surface">
50
+ <slot name="header"></slot>
51
+ <slot></slot>
52
+ <slot name="footer"></slot>
53
+ </article>
54
+ `;
55
+ }
56
+ }
57
+
58
+ export const registerVikingCard = (): void => {
59
+ defineVikingElement(VikingCard.tagName, VikingCard);
60
+ };
@@ -0,0 +1,33 @@
1
+ export const HTMLElementBase: typeof HTMLElement =
2
+ typeof HTMLElement === "undefined"
3
+ ? (class {} as unknown as typeof HTMLElement)
4
+ : HTMLElement;
5
+
6
+ export const defineVikingElement = (
7
+ tagName: string,
8
+ constructor: CustomElementConstructor,
9
+ ): void => {
10
+ if (typeof customElements === "undefined") {
11
+ return;
12
+ }
13
+
14
+ if (!customElements.get(tagName)) {
15
+ customElements.define(tagName, constructor);
16
+ }
17
+ };
18
+
19
+ export const readBooleanAttribute = (
20
+ element: HTMLElement,
21
+ name: string,
22
+ ): boolean =>
23
+ element.hasAttribute(name) && element.getAttribute(name) !== "false";
24
+
25
+ export const attributeValue = (
26
+ element: HTMLElement,
27
+ name: string,
28
+ fallback: string,
29
+ allowed?: ReadonlySet<string>,
30
+ ): string => {
31
+ const value = element.getAttribute(name) ?? fallback;
32
+ return allowed && !allowed.has(value) ? fallback : value;
33
+ };
@@ -0,0 +1,28 @@
1
+ export const resetStyles = `
2
+ :host {
3
+ box-sizing: border-box;
4
+ font-family: var(--viking-font-family);
5
+ }
6
+
7
+ *,
8
+ *::before,
9
+ *::after {
10
+ box-sizing: inherit;
11
+ }
12
+ `;
13
+
14
+ export const attachStyles = (shadow: ShadowRoot, css: string): void => {
15
+ if (
16
+ "adoptedStyleSheets" in Document.prototype &&
17
+ "replaceSync" in CSSStyleSheet.prototype
18
+ ) {
19
+ const sheet = new CSSStyleSheet();
20
+ sheet.replaceSync(css);
21
+ shadow.adoptedStyleSheets = [sheet];
22
+ return;
23
+ }
24
+
25
+ const style = document.createElement("style");
26
+ style.textContent = css;
27
+ shadow.append(style);
28
+ };
@@ -0,0 +1,154 @@
1
+ import {
2
+ defineVikingElement,
3
+ HTMLElementBase,
4
+ readBooleanAttribute,
5
+ } from "../core/dom";
6
+ import { attachStyles, resetStyles } from "../core/styles";
7
+
8
+ const styles = `
9
+ ${resetStyles}
10
+
11
+ :host {
12
+ display: contents;
13
+ }
14
+
15
+ dialog {
16
+ width: min(calc(100vw - (var(--viking-space-2) * 2)), 42rem);
17
+ padding: 0;
18
+ border: 1px solid var(--viking-border-strong);
19
+ border-radius: var(--viking-radius-lg);
20
+ background: var(--viking-surface-recipe);
21
+ color: var(--viking-text);
22
+ box-shadow: var(--viking-shadow-lg);
23
+ }
24
+
25
+ dialog::backdrop {
26
+ background: var(--viking-overlay-backdrop);
27
+ }
28
+
29
+ .modal {
30
+ display: grid;
31
+ gap: var(--viking-space-3);
32
+ padding: var(--viking-card-padding);
33
+ }
34
+
35
+ .header {
36
+ display: flex;
37
+ align-items: start;
38
+ justify-content: space-between;
39
+ gap: var(--viking-space-2);
40
+ }
41
+
42
+ .title {
43
+ margin: 0;
44
+ color: var(--viking-text);
45
+ font-size: var(--viking-font-size-lg);
46
+ line-height: var(--viking-line-height-tight);
47
+ }
48
+
49
+ .close {
50
+ display: inline-grid;
51
+ width: var(--viking-control-height-sm);
52
+ height: var(--viking-control-height-sm);
53
+ place-items: center;
54
+ border: 1px solid var(--viking-border);
55
+ border-radius: var(--viking-radius);
56
+ background: var(--viking-surface-alt);
57
+ color: var(--viking-text);
58
+ cursor: pointer;
59
+ }
60
+
61
+ .close:focus-visible {
62
+ outline: var(--viking-ring-width) solid var(--viking-ring);
63
+ outline-offset: var(--viking-ring-offset);
64
+ }
65
+ `;
66
+
67
+ export class VikingModal extends HTMLElementBase {
68
+ static readonly tagName = "viking-modal";
69
+
70
+ static get observedAttributes(): string[] {
71
+ return ["open", "label"];
72
+ }
73
+
74
+ private readonly shadowRootRef: ShadowRoot;
75
+ private dialog: HTMLDialogElement | null = null;
76
+
77
+ constructor() {
78
+ super();
79
+ this.shadowRootRef = this.attachShadow({ mode: "open" });
80
+ attachStyles(this.shadowRootRef, styles);
81
+ }
82
+
83
+ connectedCallback(): void {
84
+ this.render();
85
+ }
86
+
87
+ attributeChangedCallback(): void {
88
+ if (this.isConnected) {
89
+ this.syncOpenState();
90
+ }
91
+ }
92
+
93
+ open(): void {
94
+ this.setAttribute("open", "");
95
+ }
96
+
97
+ close(): void {
98
+ this.removeAttribute("open");
99
+ }
100
+
101
+ private render(): void {
102
+ const title = this.getAttribute("label") ?? "Dialog";
103
+ this.shadowRootRef.innerHTML = `
104
+ <dialog aria-label="${title}">
105
+ <section class="modal" part="surface">
106
+ <header class="header">
107
+ <h2 class="title"><slot name="title">${title}</slot></h2>
108
+ <button class="close" type="button" aria-label="Close dialog">x</button>
109
+ </header>
110
+ <slot></slot>
111
+ <slot name="footer"></slot>
112
+ </section>
113
+ </dialog>
114
+ `;
115
+ this.dialog = this.shadowRootRef.querySelector("dialog");
116
+ this.shadowRootRef
117
+ .querySelector(".close")
118
+ ?.addEventListener("click", () => this.close());
119
+ this.dialog?.addEventListener("close", () => {
120
+ if (this.hasAttribute("open")) {
121
+ this.removeAttribute("open");
122
+ }
123
+ this.dispatchEvent(
124
+ new CustomEvent("viking-close", { bubbles: true, composed: true }),
125
+ );
126
+ });
127
+ this.syncOpenState();
128
+ }
129
+
130
+ private syncOpenState(): void {
131
+ if (!this.dialog) {
132
+ return;
133
+ }
134
+
135
+ if (readBooleanAttribute(this, "open")) {
136
+ if (!this.dialog.open && typeof this.dialog.showModal === "function") {
137
+ this.dialog.showModal();
138
+ } else if (!this.dialog.open) {
139
+ this.dialog.setAttribute("open", "");
140
+ }
141
+ return;
142
+ }
143
+
144
+ if (this.dialog.open && typeof this.dialog.close === "function") {
145
+ this.dialog.close();
146
+ } else {
147
+ this.dialog.removeAttribute("open");
148
+ }
149
+ }
150
+ }
151
+
152
+ export const registerVikingModal = (): void => {
153
+ defineVikingElement(VikingModal.tagName, VikingModal);
154
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./web/index";
@@ -0,0 +1,62 @@
1
+ /**
2
+ * DEML branded icon paths — optimized SVG geometry (not sourced from Lucide).
3
+ * Use via viking-icon name="deml" | "deml-compact" | "deml-lockup".
4
+ */
5
+ export const VIKING_BRAND_ICON_PATHS = {
6
+ /** Primary bar-chart mark in rounded frame (outline). */
7
+ deml: '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M8 17V13M12 17V8M16 17V11"/>',
8
+ /** Compact monogram for favicons and dense Drakkar shell. */
9
+ "deml-compact":
10
+ '<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 16V12M12 16V9M15 16V13"/>',
11
+ /** Lockup mark with baseline accent bar. */
12
+ "deml-lockup":
13
+ '<rect x="3" y="3" width="18" height="14" rx="2"/><path d="M8 17V13M12 17V8M16 17V11"/><path d="M3 20h18"/>',
14
+ } as const;
15
+
16
+ /** Drakkar — Viking-UI / site shell brand marks (Lucide ship, build-time inlined). */
17
+ export const VIKING_DRAKKAR_ICON_PATHS = {
18
+ /** Primary Drakkar longship mark (outline). */
19
+ drakkar:
20
+ '<path d="M12 10.189V14"/><path d="M12 2v3"/><path d="M19 13V7a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v6"/><path d="M19.38 20A11.6 11.6 0 0 0 21 14l-8.188-3.639a2 2 0 0 0-1.624 0L3 14a11.6 11.6 0 0 0 2.81 7.76"/><path d="M2 21c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1s1.2 1 2.5 1c2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>',
21
+ /** Compact tile for favicons and dense navbar chrome. */
22
+ "drakkar-compact":
23
+ '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M12 10.189V14"/><path d="M12 2v3"/><path d="M19 13V7a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v6"/><path d="M19.38 20A11.6 11.6 0 0 0 21 14l-8.188-3.639a2 2 0 0 0-1.624 0L3 14a11.6 11.6 0 0 0 2.81 7.76"/><path d="M2 21c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1s1.2 1 2.5 1c2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>',
24
+ /** Lockup mark with baseline accent bar. */
25
+ "drakkar-lockup":
26
+ '<path d="M12 10.189V14"/><path d="M12 2v3"/><path d="M19 13V7a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v6"/><path d="M19.38 20A11.6 11.6 0 0 0 21 14l-8.188-3.639a2 2 0 0 0-1.624 0L3 14a11.6 11.6 0 0 0 2.81 7.76"/><path d="M2 21c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1s1.2 1 2.5 1c2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/><path d="M3 21h18"/>',
27
+ } as const;
28
+
29
+ /** Filled-path overrides for DEML brand marks. */
30
+ export const VIKING_BRAND_ICON_FILLED_PATHS: Partial<
31
+ Record<keyof typeof VIKING_BRAND_ICON_PATHS, string>
32
+ > = {
33
+ deml: '<path d="M5 4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4zM8 13h2.5v4H8v-4zM12 8h2.5v9H12V8zM16 11h2.5v6H16v-6z"/>',
34
+ "deml-compact":
35
+ '<path d="M6 5a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5zM9 12h1.5v4H9v-4zM12 9h1.5v7H12V9zM15 11h1.5v5H15v-5z"/>',
36
+ "deml-lockup":
37
+ '<path d="M4 4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4zM8 13h2.5v4H8v-4zM12 8h2.5v9H12V8zM16 11h2.5v6H16v-6z"/><rect x="3" y="19" width="18" height="2" rx="1"/>',
38
+ };
39
+
40
+ /** Filled-path overrides for Drakkar brand marks. */
41
+ export const VIKING_DRAKKAR_ICON_FILLED_PATHS: Partial<
42
+ Record<keyof typeof VIKING_DRAKKAR_ICON_PATHS, string>
43
+ > = {
44
+ drakkar:
45
+ '<path d="M7 5h10a2 2 0 0 1 2 2v3.5L20.8 14.2l-7.8-3.5a1.8 1.8 0 0 0-1.4 0L3.2 14.2a10.5 10.5 0 0 0 2.6 7.2L5.2 13V7a2 2 0 0 0-2-2z"/><rect x="10.85" y="2" width="2.3" height="12" rx="0.4"/>',
46
+ "drakkar-compact":
47
+ '<path d="M3 3h18a2 2 0 0 1 2 2v18a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"/><path d="M7.5 12.5 12 9.8l4.5 2.7v2.2c0 .8-.5 1.4-1.2 1.7L12 17.8l-3.3-1.6c-.7-.3-1.2-.9-1.2-1.7v-2.2z"/><rect x="11" y="6" width="2" height="5.5" rx="0.35"/>',
48
+ "drakkar-lockup":
49
+ '<path d="M7 5h10a2 2 0 0 1 2 2v3.5L20.8 14.2l-7.8-3.5a1.8 1.8 0 0 0-1.4 0L3.2 14.2a10.5 10.5 0 0 0 2.6 7.2L5.2 13V7a2 2 0 0 0-2-2z"/><rect x="10.85" y="2" width="2.3" height="12" rx="0.4"/><rect x="3" y="20" width="18" height="2" rx="1"/>',
50
+ };
51
+
52
+ export type VikingBrandIconName = keyof typeof VIKING_BRAND_ICON_PATHS;
53
+
54
+ export type VikingDrakkarIconName = keyof typeof VIKING_DRAKKAR_ICON_PATHS;
55
+
56
+ export const VIKING_BRAND_ICON_NAMES_LIST = Object.keys(
57
+ VIKING_BRAND_ICON_PATHS,
58
+ ) as VikingBrandIconName[];
59
+
60
+ export const VIKING_DRAKKAR_ICON_NAMES_LIST = Object.keys(
61
+ VIKING_DRAKKAR_ICON_PATHS,
62
+ ) as VikingDrakkarIconName[];